#Load packages
source("package_load_install.R")

#Coulour pallettes
# col_fil <- pal_jco("default")(10)
# col_scale <- scale_color_jco()
col_fil <- brewer.pal(10, "Dark2")#pal_jco("default")(10)

col_scale <- scale_fill_distiller(palette = "Dark2")

theme_set(theme_classic(base_family = "sans")) #sans = TT Arial, mono = TT courier new, serif = TT Times new roman  

source("utils.R")

#Load phyloseq objects

ps.cur <- readRDS("ps.2020_05_AMS.2020-03-31.curated.RDS")
ps.cur
## phyloseq-class experiment-level object
## otu_table()   OTU Table:         [ 2063 taxa and 180 samples ]
## sample_data() Sample Data:       [ 180 samples by 111 sample variables ]
## tax_table()   Taxonomy Table:    [ 2063 taxa by 8 taxonomic ranks ]
## phy_tree()    Phylogenetic Tree: [ 2063 tips and 2061 internal nodes ]
ps<-ps.cur

 asv_label <- function(ps, species=T, collapse_species=2){
  if (species==T){ps@tax_table[,"Species"][lapply(strsplit(ps@tax_table[,7],"/"), length)>collapse_species] <- "Ambigous"}
  label=taxa_names(ps)
  label[!is.na(ps@tax_table[,1])] <- paste0("k_",ps@tax_table[,1])[!is.na(ps@tax_table[,1])]
  label[!is.na(ps@tax_table[,2])] <- paste0("p_",ps@tax_table[,2])[!is.na(ps@tax_table[,2])]
  label[!is.na(ps@tax_table[,3])] <- paste0("c_",ps@tax_table[,3])[!is.na(ps@tax_table[,3])]
  label[!is.na(ps@tax_table[,4])] <- paste0("o_",ps@tax_table[,4])[!is.na(ps@tax_table[,4])]
  label[!is.na(ps@tax_table[,5])] <- paste0("f_",ps@tax_table[,5])[!is.na(ps@tax_table[,5])]
  label[!is.na(ps@tax_table[,6])] <- paste0("g_",ps@tax_table[,6])[!is.na(ps@tax_table[,6])]
  if (species==T){
    label[!is.na(ps@tax_table[,7])] <- paste0("s_",ps@tax_table[,6],"_", ps@tax_table[,7])[!is.na(ps@tax_table[,7])]}
  label <- make.unique(label)
  return(label)
}

taxa_names(ps.cur) <- asv_label(ps.cur)

#Rename ambigous species names
rename_entries <- function(x) {
  if_else(str_count(x, "/") > 1, "Ambigous", x)
}

taxa.names <- taxa_names(ps.cur)

tax.nonamb <- ps.cur@tax_table %>% as.data.frame() %>% mutate(across(Species, rename_entries))

row.names(tax.nonamb) <- taxa.names
head(tax.nonamb)
tax_table(ps.cur) <- as(tax.nonamb,"matrix")

#Use curated, ASV relabbeled OTU table for analysis
PSB <- ps.cur

Pre-processing

Merge metadata

Only run for original non-randomized metadata

meta.microbiome <- readxl::read_xlsx("1. Metadata - Microbiome Excel characteristics.xlsx")
meta.24hfood <- readxl::read_xlsx("3. Metadata - Microbiome Excel 24h food intake.xlsx")
meta.cortisol <- readxl::read_xlsx("Cortisol_variabelen_microbiome.xlsx")
#meta.ffqfood <- readxl::read_xlsx("4. Metadata - Microbiome Excel FFQ food intake.xlsx")
meta.outcomes <- readxl::read_xlsx("Infant outcomes.xlsx") %>% dplyr::rename(AMS_ID = Subject_ID)


meta.dat <- data.frame(sample_data(PSB))
meta.dat$ID <- meta.dat$Ext_ID

meta <- dplyr::left_join(meta.dat,meta.microbiome,by="ID")
meta <- dplyr::left_join(meta,meta.cortisol,by="ID")
meta <- dplyr::left_join(meta,meta.24hfood,by="ID")

meta <- meta %>% tidyr::separate_wider_regex(Int_ID, c(AMS_ID = ".*", "_", Timecode = ".*"),cols_remove=FALSE)#Split internal id to separate id and timepint code

meta <- dplyr::left_join(meta,meta.outcomes,by="AMS_ID",keep=FALSE) #Do not keep non-matched IDs as these are for excluded infants
#meta <- dplyr::left_join(meta,meta.ffqfood,by="ID")

meta <- type.convert(meta) %>% as.data.frame()

rownames(meta) <- rownames(meta.dat)

sample_data(PSB) <- meta

saveRDS(PSB,"AMS_phyloseq.RDS")

All metadata columns:

sort(colnames(meta))
##   [1] "ALA_g"                            "Alcohol_.g."                     
##   [3] "Alcohol_totaal_en%"               "Alcohol_totaal_g"                
##   [5] "AMP_Plate_ID"                     "AMS_ID"                          
##   [7] "Antibio_Name"                     "Antibio_Per"                     
##   [9] "Antibio_Use.x"                    "Antibio_Use.y"                   
##  [11] "Available"                        "Bio_Safety_Level"                
##  [13] "Birth_weight_child"               "BMI_mother"                      
##  [15] "Bristol_Scale"                    "Calcium_.mg."                    
##  [17] "Calcium_mg"                       "Cholesterol_mg"                  
##  [19] "Collection_Date"                  "Collection_Time"                 
##  [21] "Contact_AMC"                      "Contact_Person_Email"            
##  [23] "Date_add_Meta"                    "Datum_moment1"                   
##  [25] "Datum_moment2"                    "Datum_moment3"                   
##  [27] "Department"                       "DHA_g"                           
##  [29] "Diet_Journal"                     "Education_mother"                
##  [31] "Eiwit_.g."                        "Eiwit_dierlijk_g"                
##  [33] "Eiwit_plantaardig_g"              "Eiwit_totaal_en%"                
##  [35] "Eiwit_totaal_g"                   "Energie_.kcal."                  
##  [37] "Energie_kcal"                     "Energie_kjoule"                  
##  [39] "EPA_g"                            "EPDS_stress_score"               
##  [41] "Ethnicity_mother"                 "Ext_ID"                          
##  [43] "Foliumzuur_.ug."                  "Follow_ID"                       
##  [45] "Folaat_equivalenten_ug"           "Folaat_ug"                       
##  [47] "Foodscore_g"                      "Gender_child"                    
##  [49] "Geo_Loc_Name"                     "Hair cortisol"                   
##  [51] "Health_mother"                    "HM_cortisol_AUC_1"               
##  [53] "HM_cortisol_AUC_2"                "HM_cortisol_morning_peak_1"      
##  [55] "HM_cortisol_morning_peak_2"       "Hospitalized_child"              
##  [57] "Host_Age_Years"                   "Host_body_Mass_Index"            
##  [59] "Host_Body_Product"                "Host_Body_Site"                  
##  [61] "Host_Common_Name"                 "Host_Diet"                       
##  [63] "Host_Health"                      "Host_Height"                     
##  [65] "Host_Sex"                         "Host_Taxid"                      
##  [67] "Host_Tot_Mass"                    "ID"                              
##  [69] "Ijzer_.mg."                       "IJzer_haem_mg"                   
##  [71] "IJzer_non_haem_mg"                "IJzer_totaal_mg"                 
##  [73] "Index_Name"                       "Infant_headc_3m"                 
##  [75] "Infant_headc_w2"                  "Infant_headc_w4"                 
##  [77] "Infant_headc_w8"                  "Infant_lengt_3M"                 
##  [79] "Infant_lengt_w2"                  "Infant_lengt_w4"                 
##  [81] "Infant_lengt_w8"                  "Infant_sleep_>6"                 
##  [83] "Infant_sleep_day"                 "Infant_sleep_naps"               
##  [85] "Infant_sleep_night"               "Infant_sleep_wake"               
##  [87] "Infant_temp_act"                  "Infant_temp_app"                 
##  [89] "Infant_temp_cudd"                 "Infant_temp_dist"                
##  [91] "Infant_temp_dura"                 "Infant_temp_fall"                
##  [93] "Infant_temp_fear"                 "Infant_temp_hip"                 
##  [95] "Infant_temp_lip"                  "Infant_temp_NEG"                 
##  [97] "Infant_temp_perc"                 "Infant_temp_REG"                 
##  [99] "Infant_temp_sad"                  "Infant_temp_smile"               
## [101] "Infant_temp_soot"                 "Infant_temp_SUR"                 
## [103] "Infant_temp_voc"                  "Infant_weight_3m"                
## [105] "Infant_weight_w2"                 "Infant_weight_w4"                
## [107] "Infant_weight_w8"                 "Input"                           
## [109] "Int_ID"                           "Jodium_.ug."                     
## [111] "JTVEA_stress_score"               "JTVEN_stress_score"              
## [113] "JTVPA_stress_score"               "JTVPN_stress_score"              
## [115] "JTVSA_stress_score"               "Kalium_.mg."                     
## [117] "Koolhydr_.g."                     "Koolhydraten_totaal_en%"         
## [119] "Koolhydraten_totaal_g"            "Lib_Conc_final"                  
## [121] "Lib_Conc_sub"                     "Lib_Const_Meth"                  
## [123] "Lib_Pool"                         "Lib_Ratio"                       
## [125] "Lib_Size"                         "Library_ID"                      
## [127] "Linolzuur_g"                      "LSCr_stress_score"               
## [129] "Magnesium_.mg."                   "Magnesium_mg"                    
## [131] "Maternal_age"                     "Methionine_mg"                   
## [133] "Mid_F"                            "Mid_R"                           
## [135] "Modus_partus"                     "Mono_en_disacchariden_totaal_g"  
## [137] "Natrium_.mg."                     "Nicotinezuur_.mg."               
## [139] "Nicotinezuur_mg"                  "Nucl_Acid_260230"                
## [141] "Nucl_Acid_260280"                 "Nucl_Acid_Amp"                   
## [143] "Nucl_Acid_AMP_Conc"               "Nucl_Acid_Amp_ID"                
## [145] "Nucl_Acid_AMP_Used"               "Nucl_Acid_Beat_ID"               
## [147] "Nucl_Acid_Buffer_Date"            "Nucl_Acid_Conc"                  
## [149] "Nucl_Acid_Ext"                    "Nucl_Acid_Ext_ID"                
## [151] "Nucl_Acid_Iso_Date"               "PCR_Cond"                        
## [153] "PCR_Primers"                      "Polysacchariden_totaal_g"        
## [155] "Primary_Test_Var"                 "Project_name"                    
## [157] "PSS_stress_score"                 "reads_Chloroplast"               
## [159] "reads_Contaminants"               "reads_mapped"                    
## [161] "reads_merged"                     "reads_Mitochondria"              
## [163] "reads_pf"                         "reads_phix"                      
## [165] "reads_total"                      "Remarks"                         
## [167] "Retinol_activiteit_equiv.RAE_ug"  "Saliva_cortisol_morning_peak"    
## [169] "Samp_Collect_Device"              "Samp_Mat_Process"                
## [171] "Samp_Size"                        "Samp_Store_Date_AMC"             
## [173] "Samp_Store_Loc_AMC"               "Samp_Store_Temp_AMC"             
## [175] "Samp_Store_Temp_Local"            "Samp_Vol_We_DNA_Ext"             
## [177] "Season_milk_collection"           "Selenium_.ug."                   
## [179] "Seq_ID"                           "Seq_Meth"                        
## [181] "SOP"                              "STAIs_stress_score"              
## [183] "STAIt_stress_score"               "Study_group"                     
## [185] "Subject_ID"                       "Target_Gene"                     
## [187] "Target_Subfragment"               "Time_point"                      
## [189] "Time_Point"                       "Timecode"                        
## [191] "timepoint"                        "Timepoint"                       
## [193] "Verz_vet_.g."                     "Vet_.g."                         
## [195] "Vet_totaal_en%"                   "Vet_totaal_g"                    
## [197] "Vetzuren_enkelv_onverz_g"         "Vetzuren_meerv_onverz_g"         
## [199] "Vetzuren_n-3_meerv_onverz_cis_g"  "Vetzuren_n-6_meerv_onverz__cis_g"
## [201] "Vetzuren_totaal_trans_g"          "Vetzuren_totaal_verzadigd_g"     
## [203] "Vezels_.g."                       "Vit_A_.ug."                      
## [205] "Vit_B1_.mg."                      "Vit_B12_.ug."                    
## [207] "Vit_B2_.mg."                      "Vit_B6_.mg."                     
## [209] "Vit_C_.mg."                       "Vit_D_.ug."                      
## [211] "Vit_E_.mg."                       "Vitamine_B1_mg"                  
## [213] "Vitamine_B12_ug"                  "Vitamine_B2_mg"                  
## [215] "Vitamine_B6_totaal_mg"            "Vitamine_C_mg"                   
## [217] "Vitamine_D_totaal_ug"             "Vitamine_E_totaal_mg"            
## [219] "Voedingsvezel_totaal_en%"         "Voedingsvezel_totaal_g"          
## [221] "Water_.g."                        "Your_Name"                       
## [223] "Zink_.mg."                        "Zink_mg"                         
## [225] "Zout_.g."                         "Aantal_vm"

Load randomized metadat

PSB <- readRDS("AMS_phyloseq.RDS")
#readRDS("AMS_phyloseq_randomized.RDS")

Remove ASV fasta sequence column

PSB@tax_table <- tax_table(PSB)[,1:7]

Format metadata

Format stress group column

Rename gender to sex

Calculate WHZ scores - not done yet

meta.dat$`Weight month 1` <- as.numeric(meta.dat$`Weight month 1`)
meta.dat$`Weight month 6` <- as.numeric(meta.dat$`Weight month 6`)

meta.dat$`Height month 1` <- as.numeric(meta.dat$`Height month 1`)
meta.dat$`Height month 6` <- as.numeric(meta.dat$`Height month 6`)

meta.dat$`30days` <- 30
meta.dat$`180days` <- 180

svy <- addWGSR(data = anthro3, sex = "sex", firstPart = "weight",
               secondPart = "height", index = "wfh")
# Weight for height
meta.dat <- addWGSR(data = meta.dat, sex = "Infant sex", firstPart = "Weight month 1",
               secondPart = "Height month 1", index = "wfl", output = "whz.1m")

meta.dat <- addWGSR(data = meta.dat, sex = "Infant sex", firstPart = "Weight month 6",
               secondPart = "Height month 6", index = "wfl", output = "whz.6m")

meta.dat$delta.whz <- meta.dat$whz.6m - meta.dat$whz.1m

# Height for age
meta.dat <- addWGSR(data = meta.dat, sex = "Infant sex", firstPart = "Height month 1",
               secondPart = 'Sample_age(1MO)', index = "lfa", output = "haz.1m")

meta.dat <- addWGSR(data = meta.dat, sex = "Infant sex", firstPart = "Height month 6",
               secondPart = '180days', index = "lfa", output = "haz.6m")

meta.dat$delta.haz <- meta.dat$haz.6m - meta.dat$haz.1m

#Weight for age

meta.dat <- addWGSR(data = meta.dat, sex = "Infant sex", firstPart = "Weight month 1",
               secondPart = 'Sample_age(1MO)', index = "lfa", output = "waz.1m")

meta.dat <- addWGSR(data = meta.dat, sex = "Infant sex", firstPart = "Weight month 6",
               secondPart = '180days', index = "lfa", output = "waz.6m")

meta.dat$delta.waz <- meta.dat$waz.6m - meta.dat$waz.1m

Define key variables

#colnames(meta.outcomes)

key.vars <- c("Stress_group",
           "Sex_child",
           "PSS_stress_score",
           "LSCr_stress_score",
           "Education_mother",
           "BMI_mother",
           "Timepoint"
           # "Hair cortisol",
           # "HM_cortisol_AUC_1",
           #"Saliva_cortisol_morning_peak"
                      )

key.vars.inf <- c("Infant_temp_NEG",
           "Infant_temp_REG",
           "Infant_temp_SUR",
           "Infant_weight_w2",
           "Infant_weight_3m",
           "Timepoint"
)

key.vars.cortisol <- c("Hair cortisol",
           "HM_cortisol_AUC_1",
           "HM_cortisol_AUC_2",
           # "HM_cortisol_morning_peak_1",
           # "HM_cortisol_morning_peak_2",
           "Saliva_cortisol_morning_peak",
           "Timepoint"
)
meta <- sample_data(PSB) %>% unclass() %>% as.data.frame()

Filtering

Remove low-abundance ASVs

Remove taxa not seen found in at least 3 samples with a total count of minimum 1000 reads. This protects against an OTU with small mean & trivially large C.V.

prev <- 3/nrow(PSB@sam_data)
PSB.fil = metagMisc::phyloseq_filter_prevalence(PSB, prev.trh = prev, abund.trh = 500, abund.type = "total", threshold_condition = "AND")

spec <- specnumber(as.matrix(otu_table(PSB.fil))) %>% sort(decreasing=FALSE)
head(spec)
## 2020_0002_00_SA506SA703 2020_0002_00_SB503SA702 2020_0002_00_SA507SA704 
##                      16                      18                      25 
## 2020_0002_00_SA505SA703 2020_0002_00_SB501SA701 2020_0002_00_SB505SA703 
##                      25                      28                      28
sum(sample_sums(PSB.fil))/sum(sample_sums(PSB))
## [1] 0.9753507
PSB <- PSB.fil

97.5% of reads were kept after filtering, but number of taxa reduced from 2063 to 250

CSS normalization

Save objects

meta <- PSB@sam_data %>% as.data.frame()

save(list=c("PSB","PSB.CSS","meta","key.vars","key.vars.inf","key.vars.cortisol"),
    file = "Curated_AMS.RData"
    )

Read count per sample

## 2020_0002_00_SA501SA701 2020_0002_00_SA503SA703 2020_0002_00_SA505SA705 
##                   12170                    3138                   33535 
## 2020_0002_00_SA507SA707 2020_0002_00_SA501SA702 2020_0002_00_SA503SA704 
##                    7083                   47267                   11266 
## 2020_0002_00_SA505SA706 2020_0002_00_SA507SA708 2020_0002_00_SA501SA703 
##                   48087                   68730                   11609 
## 2020_0002_00_SA503SA705 2020_0002_00_SA505SA707 2020_0002_00_SA507SA709 
##                   59026                   15570                   61885 
## 2020_0002_00_SA501SA704 2020_0002_00_SA503SA706 2020_0002_00_SA506SA709 
##                    9701                   30514                    2392 
## 2020_0002_00_SA508SA711 2020_0002_00_SA502SA706 2020_0002_00_SA504SA708 
##                   42542                   28729                   31251 
## 2020_0002_00_SA506SA710 2020_0002_00_SA508SA712 2020_0002_00_SA502SA707 
##                    5699                   48619                   49937 
## 2020_0002_00_SA504SA709 2020_0002_00_SA506SA711 2020_0002_00_SA508SA701 
##                    1395                   24927                   42264 
## 2020_0002_00_SA502SA708 2020_0002_00_SA504SA710 2020_0002_00_SA506SA712 
##                   40988                   29354                    7819 
## 2020_0002_00_SA508SA702 2020_0002_00_SA501SA708 2020_0002_00_SA503SA710 
##                   30524                   21012                   48867 
## 2020_0002_00_SA505SA712 2020_0002_00_SA507SA702 2020_0002_00_SA501SA709 
##                    6856                   31086                   55488 
## 2020_0002_00_SA503SA711 2020_0002_00_SA506SA702 2020_0002_00_SA508SA704 
##                    8145                    8709                   22643 
## 2020_0002_00_SA502SA711 2020_0002_00_SA504SA701 2020_0002_00_SA506SA703 
##                   10307                    9782                     128 
## 2020_0002_00_SA508SA705 2020_0002_00_SA502SA712 2020_0002_00_SA504SA702 
##                   30130                   13361                     771 
## 2020_0002_00_SA506SA704 2020_0002_00_SA508SA706 2020_0002_00_SA501SA712 
##                    5410                   12356                    1358 
## 2020_0002_00_SA503SA702 2020_0002_00_SB501SA701 2020_0002_00_SB503SA703 
##                   44124                     692                    9309 
## 2020_0002_00_SB505SA705 2020_0002_00_SB507SA707 2020_0002_00_SB501SA702 
##                    2080                   18798                   54142 
## 2020_0002_00_SB503SA704 2020_0002_00_SB505SA706 2020_0002_00_SB507SA708 
##                   13047                   14933                   21337 
## 2020_0002_00_SB501SA703 2020_0002_00_SB503SA705 2020_0002_00_SB505SA707 
##                   10725                    4224                   50136 
## 2020_0002_00_SB507SA709 2020_0002_00_SB501SA704 2020_0002_00_SB503SA706 
##                   40828                   52600                    2550 
## 2020_0002_00_SB505SA708 2020_0002_00_SB507SA710 2020_0002_00_SB501SA705 
##                    3664                   30507                    5999 
## 2020_0002_00_SB502SA706 2020_0002_00_SB504SA708 2020_0002_00_SB506SA710 
##                   10435                    3817                    8431 
## 2020_0002_00_SB508SA712 2020_0002_00_SB502SA707 2020_0002_00_SB504SA709 
##                   52132                   50619                   74594 
## 2020_0002_00_SB506SA711 2020_0002_00_SB508SA701 2020_0002_00_SB502SA708 
##                   55369                    7339                   11666 
## 2020_0002_00_SB505SA711 2020_0002_00_SB507SA701 2020_0002_00_SB501SA708 
##                   25040                    6529                   43807 
## 2020_0002_00_SB503SA710 2020_0002_00_SB505SA712 2020_0002_00_SB507SA702 
##                   19514                   11295                   26850 
## 2020_0002_00_SB501SA709 2020_0002_00_SB503SA711 2020_0002_00_SB505SA701 
##                    9058                    4869                   41397 
## 2020_0002_00_SB507SA703 2020_0002_00_SB501SA710 2020_0002_00_SB503SA712 
##                    2612                   47965                   26051 
## 2020_0002_00_SB505SA702 2020_0002_00_SB507SA704 2020_0002_00_SB508SA705 
##                   37514                   16116                    6926 
## 2020_0002_00_SB502SA712 2020_0002_00_SB504SA702 2020_0002_00_SB506SA704 
##                   49883                    9721                   70143 
## 2020_0002_00_SB508SA706 2020_0002_00_SB502SA701 2020_0002_00_SA502SA702 
##                   35261                   10753                    8892 
## 2020_0002_00_SA504SA704 2020_0002_00_SA506SA706 2020_0002_00_SA508SA708 
##                    6553                    6899                     583 
## 2020_0002_00_SA502SA703 2020_0002_00_SA504SA705 2020_0002_00_SA506SA707 
##                   32340                    9470                    3065 
## 2020_0002_00_SA508SA709 2020_0002_00_SA502SA704 2020_0002_00_SA504SA706 
##                   35659                   41367                    1226 
## 2020_0002_00_SA506SA708 2020_0002_00_SA508SA710 2020_0002_00_SA502SA705 
##                    3670                   35748                   42246 
## 2020_0002_00_SA504SA707 2020_0002_00_SA507SA710 2020_0002_00_SA501SA705 
##                   48837                   46943                   13095 
## 2020_0002_00_SA503SA707 2020_0002_00_SA505SA709 2020_0002_00_SA507SA711 
##                    8567                   95344                    3124 
## 2020_0002_00_SA501SA706 2020_0002_00_SA503SA708 2020_0002_00_SA505SA710 
##                   39168                    4801                    3880 
## 2020_0002_00_SA507SA712 2020_0002_00_SA501SA707 2020_0002_00_SA503SA709 
##                   55561                   45894                   45512 
## 2020_0002_00_SA505SA711 2020_0002_00_SA507SA701 2020_0002_00_SA502SA709 
##                    7868                   48035                   16526 
## 2020_0002_00_SA504SA711 2020_0002_00_SA506SA701 2020_0002_00_SA508SA703 
##                    8544                    9087                   85395 
## 2020_0002_00_SA502SA710 2020_0002_00_SA505SA701 2020_0002_00_SA507SA703 
##                   55120                    4297                    6078 
## 2020_0002_00_SA501SA710 2020_0002_00_SA503SA712 2020_0002_00_SA505SA702 
##                   60214                    6021                   22725 
## 2020_0002_00_SA507SA704 2020_0002_00_SA501SA711 2020_0002_00_SA503SA701 
##                     319                    6439                   15568 
## 2020_0002_00_SA505SA703 2020_0002_00_SA507SA705 2020_0002_00_SA502SA701 
##                    1336                   13544                    1610 
## 2020_0002_00_SA504SA703 2020_0002_00_SB502SA702 2020_0002_00_SB504SA704 
##                   50243                    1844                   27496 
## 2020_0002_00_SB506SA706 2020_0002_00_SB508SA708 2020_0002_00_SB502SA703 
##                   12405                    2212                   35592 
## 2020_0002_00_SB504SA705 2020_0002_00_SB506SA707 2020_0002_00_SB508SA709 
##                   40231                   55148                   56956 
## 2020_0002_00_SB502SA704 2020_0002_00_SB504SA706 2020_0002_00_SB506SA708 
##                    8227                    7126                   12352 
## 2020_0002_00_SB508SA710 2020_0002_00_SB502SA705 2020_0002_00_SB504SA707 
##                   29074                   41753                   44304 
## 2020_0002_00_SB506SA709 2020_0002_00_SB508SA711 2020_0002_00_SB503SA707 
##                    3141                    1099                   11251 
## 2020_0002_00_SB505SA709 2020_0002_00_SB507SA711 2020_0002_00_SB501SA706 
##                    6979                   36706                   38258 
## 2020_0002_00_SB503SA708 2020_0002_00_SB505SA710 2020_0002_00_SB507SA712 
##                   44937                   35155                   46866 
## 2020_0002_00_SB501SA707 2020_0002_00_SB503SA709 2020_0002_00_SB506SA712 
##                   20985                    2817                   49570 
## 2020_0002_00_SB508SA702 2020_0002_00_SB502SA709 2020_0002_00_SB504SA711 
##                   64960                   34917                   21633 
## 2020_0002_00_SB506SA701 2020_0002_00_SB508SA703 2020_0002_00_SB502SA710 
##                    9238                   17224                   33517 
## 2020_0002_00_SB504SA712 2020_0002_00_SB506SA702 2020_0002_00_SB508SA704 
##                    3146                   51669                    2157 
## 2020_0002_00_SB502SA711 2020_0002_00_SB504SA701 2020_0002_00_SB506SA703 
##                   38319                   44373                    2536 
## 2020_0002_00_SB501SA711 2020_0002_00_SB503SA701 2020_0002_00_SB505SA703 
##                    4510                   64187                    2007 
## 2020_0002_00_SB507SA705 2020_0002_00_SB501SA712 2020_0002_00_SB503SA702 
##                   46335                   41297                     508

Barplots

All samples

Genus

Samples look quite similar in compostion, apart from sample 37281 and 37291. 377281 had very low observed ASV count, so it is removed.

Phylum

By stress group

By time point

By Stess and time point

Genus

### Phylum

Relative abundance violin plot

Stress group

#remotes::install_github("jstokholm/rabuplot")
library(rabuplot)

rabu.group <- rabuplot(
  PSB,
  violin = TRUE, predictor = "Stress_group", p_adjust = TRUE, p_stars = TRUE ,colors = col_fil[1:2],text_angle_x = 45)

rabu.group <- rabu.group + 
   guides(fill=guide_legend("Stress group")) 

rabu.group

Adjusted for timepoint

rabu.group.adj_time <- rabuplot(
  PSB,
  violin = TRUE, predictor = "Stress_group",
  Time  = "Timecode",
  p_adjust = TRUE, p_stars = TRUE ,colors = col_fil[1:2], stats = "non-parametric")

rabu.group.adj_time

Subject id

rabu.group.adj_time <- rabuplot(
  PSB,
  violin = TRUE, predictor = "Stress_group", id="Subject_ID",p_adjust = TRUE, p_stars = TRUE ,colors = col_fil[1:2])

rabu.group.adj_time

Species

#remotes::install_github("jstokholm/rabuplot")
library(rabuplot)

rabu.group.species <- rabuplot(
  PSB,
  violin = TRUE, predictor = "Stress_group", p_adjust = TRUE, p_stars = TRUE ,colors = col_fil[1:2],type="Species")

rabu.group.species

Time

rabu.time <- rabuplot(
  PSB,
  violin = TRUE, predictor = "Day", p_adjust = TRUE, p_stars = TRUE ,colors = col_fil[1:2])

rabu.time

Study group over time

rabu.group.time <- rabuplot(
  PSB,
  violin = TRUE, predictor = "Stress_group", facet_wrap = "Day", p_adjust = TRUE, p_stars = TRUE ,colors = col_fil[1:2]) + 
   guides(fill=guide_legend("Stress group")) +
            ggtitle("")

rabu.group.time

Alpha diversity

Stress group

Anova

##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = Shannon ~ variable, data = rich)
## 
## $variable
##                      diff        lwr        upr     p adj
## Stress-Control -0.1118888 -0.3039283 0.08015081 0.2517858

Time

Anova

##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = Shannon ~ variable, data = rich)
## 
## $variable
##                diff      lwr      upr     p adj
## p24-p10 -0.01552703 -0.18248 0.151426 0.8545917

Beta diversity

Group

Permanova statistics

Timepoint

Permanova statistics

Stress split by time

#Permanova

Permanova - time points separately

Differential abundance - Deseq2

Deseq 2 Mao style

Run deseq2

ps <- PSB
ps <- tax_glom(ps, "Species", NArm = FALSE) #select a level to compare


library(DESeq2)
  
  # remove all error taxa
  ps.ds <- phyloseq_to_deseq2(ps, ~Stress_group + Timepoint)
  # solve rows without a zero, deseq need to calculate the geometric zero, 
  cts <- counts(ps.ds)
  geoMeans <- apply(cts, 1, function(row) if (all(row == 0)) 0 else exp(mean(log(row[row != 0]))))
  dds <- estimateSizeFactors(ps.ds, geoMeans=geoMeans)
  ps.ds <-  DESeq2::DESeq(dds, test="Wald", fitType="parametric")
  # result
  res = results(ps.ds, cooksCutoff = FALSE)
  sigtab = res
  sigtab = cbind(as(sigtab, "data.frame"), as(tax_table(ps)[rownames(sigtab), ], "matrix"))
  head(sigtab)

Volcano

EnhancedVolcano::EnhancedVolcano(sigtab,
    lab =  sub("^[^_]*_", "", rownames(res)),
    x = 'log2FoldChange',
    y = 'pvalue',
    pCutoff = 0.05,
    FCcutoff = 0.5)

Log-fold change boxplot

# Select significant ASVs

tab <- subset(sigtab, padj < 0.05)

OTU <- unique(tab)

##
ps.rel <- transform_sample_counts(PSB, function(x) x/sum(x)*100)
ps.rel.sig <- prune_taxa(colnames(otu_table(ps.rel)) %in% rownames(OTU) , ps.rel)
## at least 1% relative abundance appearance in 1% samples
mat <- as.matrix(otu_table(ps.rel.sig))
species2keep <- colnames(mat)[rowSums(mat>=2)/length(colnames(mat))> 0.1]
species2keep <- species2keep[!is.na(species2keep)]
sigtab.p.prev <- tab[species2keep,]

sigtabgen = subset(sigtab.p.prev, !is.na(Genus))

# Phylum order
x = tapply(sigtabgen$log2FoldChange, sigtabgen$Phylum, function(x) max(x))
x = sort(x, TRUE)
sigtabgen$Phylum = factor(as.character(sigtabgen$Phylum), levels=names(x))
# Genus order
x = tapply(sigtabgen$log2FoldChange, sigtabgen$Genus, function(x) max(x))
x = sort(x, TRUE)
sigtabgen$Genus = factor(as.character(sigtabgen$Genus), levels=names(x))

ggplot(sigtabgen, aes(y=Genus, x=log2FoldChange, color=Phylum)) + 
  geom_vline(xintercept = 0.0, color = "gray", size = 0.5) +
  geom_boxplot() + 
  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust=0.5)) +
  scale_color_manual(values = col_fil[3:4])

deseq2.log2fold.box <- ggplot(sigtabgen, aes(y=Genus, x=log2FoldChange, color=Family)) + 
  geom_vline(xintercept = 0.0, color = "gray", size = 0.5) +
  geom_boxplot() + 
  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust=0.5),
        #plot.margin = margin(2, 0, 0, 0, "cm")
        ) +
  scale_color_manual(values = col_fil) +
  ylab("ASV genus") +
  ggtitle("\U2190 Controls        HS \U2192")

deseq2.log2fold.box

Heatmap

  theme_set(theme_bw())
  
  scale_fill_discrete <- function(palname = "Set1", ...) {
    scale_fill_brewer(palette = palname, ...)
  }
  
  
tab <- subset(sigtab, padj < 0.05)

OTU <- unique(tab)

ps.rel <- transform_sample_counts(ps, function(x) x/sum(x)*100)
ps.rel.sig <- prune_taxa(colnames(otu_table(ps.rel)) %in% rownames(OTU) , ps.rel)

#select the rel-abun > 0.1%

# at least 1% relative abundance appearance in 5% samples
mat <- as.matrix(otu_table(ps.rel.sig))
species2keep <- colnames(mat)[rowSums(mat>=1)/length(colnames(mat))> 0.1]
species2keep
##   [1] "s_Enterobacter_Ambigous.3"          "s_Klebsiella_Ambigous.3"           
##   [3] "s_Acinetobacter_Ambigous.3"         "g_Acinetobacter.40"                
##   [5] "s_Stenotrophomonas_maltophilia.9"   "g_Veillonella.18"                  
##   [7] "s_Gemella_Ambigous"                 "s_Streptococcus_Ambigous.5"        
##   [9] "s_Lactobacillus_Ambigous.2"         "s_Klebsiella_michiganensis/oxytoca"
##  [11] NA                                   NA                                  
##  [13] NA                                   NA                                  
##  [15] NA                                   NA                                  
##  [17] NA                                   NA                                  
##  [19] NA                                   NA                                  
##  [21] NA                                   NA                                  
##  [23] NA                                   NA                                  
##  [25] NA                                   NA                                  
##  [27] NA                                   NA                                  
##  [29] NA                                   NA                                  
##  [31] NA                                   NA                                  
##  [33] NA                                   NA                                  
##  [35] NA                                   NA                                  
##  [37] NA                                   NA                                  
##  [39] NA                                   NA                                  
##  [41] NA                                   NA                                  
##  [43] NA                                   NA                                  
##  [45] NA                                   NA                                  
##  [47] NA                                   NA                                  
##  [49] NA                                   NA                                  
##  [51] NA                                   NA                                  
##  [53] NA                                   NA                                  
##  [55] NA                                   NA                                  
##  [57] NA                                   NA                                  
##  [59] NA                                   NA                                  
##  [61] NA                                   NA                                  
##  [63] NA                                   NA                                  
##  [65] NA                                   NA                                  
##  [67] NA                                   NA                                  
##  [69] NA                                   NA                                  
##  [71] NA                                   NA                                  
##  [73] NA                                   NA                                  
##  [75] NA                                   NA                                  
##  [77] NA                                   NA                                  
##  [79] NA                                   NA                                  
##  [81] NA                                   NA                                  
##  [83] NA                                   NA                                  
##  [85] NA                                   NA                                  
##  [87] NA                                   NA                                  
##  [89] NA                                   NA                                  
##  [91] NA                                   NA                                  
##  [93] NA                                   NA                                  
##  [95] NA                                   NA                                  
##  [97] NA                                   NA                                  
##  [99] NA                                   NA                                  
## [101] NA                                   NA                                  
## [103] NA                                   NA                                  
## [105] NA                                   NA                                  
## [107] NA                                   NA                                  
## [109] NA                                   NA                                  
## [111] NA                                   NA                                  
## [113] NA                                   NA                                  
## [115] NA                                   NA                                  
## [117] NA                                   NA                                  
## [119] NA                                   NA                                  
## [121] NA                                   NA                                  
## [123] NA                                   NA                                  
## [125] NA                                   NA                                  
## [127] NA                                   NA                                  
## [129] NA                                   NA                                  
## [131] NA                                   NA                                  
## [133] NA                                   NA                                  
## [135] NA                                   NA                                  
## [137] NA                                   NA                                  
## [139] NA                                   NA                                  
## [141] NA                                   NA                                  
## [143] NA                                   NA                                  
## [145] NA                                   NA                                  
## [147] NA                                   NA                                  
## [149] NA                                   NA                                  
## [151] NA                                   NA                                  
## [153] NA                                   NA                                  
## [155] NA                                   NA                                  
## [157] NA                                   NA                                  
## [159] NA                                   NA                                  
## [161] NA                                   NA                                  
## [163] NA                                   NA                                  
## [165] NA                                   NA                                  
## [167] NA                                   NA
ps.rel.sig <- prune_taxa(species2keep,ps.rel.sig)

otu_abun_select <- data.frame(otu_table(ps.rel.sig), check.names = F)

#import relavant metadata
metadata <- data.frame(sample_data(ps.rel.sig))
tax.clean <- data.frame(tax_table(ps.rel.sig))


# create a variable to define the subgroup
# order the matrix by the subgroup
# metadata$Treatment <- factor(metadata$Treatment, levels = groups)
# meta_order <- metadata[order(metadata$Treatment),]

# # re_order the col
# mat <- otu_abun_select
# mat <- as.matrix(mat[,rownames(meta_order)])

base_mean = rowMeans(mat)
mat_scaled = t(scale(t(mat)))

# calculate heatmap annotation
tax_heatmap <- tax.clean[colnames(mat_scaled),]

tax_heatmap$sign <- sapply(rownames(tax_heatmap), function(x) ifelse(x %in% rownames(sigtab),"*","ns"))

index <- match(rownames(tax_heatmap), rownames(tab))
index
##  [1]  1  2  3  4 NA  6  7 NA  9 10 11 12
tax_heatmap$p_val <- tab$padj[index]

tax_heatmap <- tax_heatmap[order(tax_heatmap$p_val),]

max(c(-log10(tax_heatmap$p_val)))
## [1] NA
# my_palette <- c("darkblue", "darkgoldenrod1", "darkseagreen", "darkorchid", "darkolivegreen1", "lightskyblue", "darkgreen",
#                 "deeppink", "khaki2", "firebrick", "brown1", "darkorange1", "cyan1", "royalblue4", "darksalmon", "darkblue", 
#                 "royalblue4", "dodgerblue3", "steelblue1", "lightskyblue", "darkseagreen", "darkgoldenrod1", "darkseagreen", 
#                 "darkorchid", "darkolivegreen1", "brown1", "darkorange1", "cyan1", "darkgrey", "darkblue", "darkgoldenrod1", 
#                 "darkseagreen", "darkorchid", "darkolivegreen1", "lightskyblue", "darkgreen", "deeppink", "khaki2", 
#                 "firebrick", "brown1", "darkorange1", "cyan1", "royalblue4", "darksalmon", "darkblue", "royalblue4", 
#                 "dodgerblue3", "steelblue1", "lightskyblue", "darkseagreen", "darkgoldenrod1", "darkseagreen", "darkorchid", 
#                 "darkolivegreen1", "brown1", "darkorange1", "cyan1", "darkgrey")

my_palette <- rep(col_fil,5)

# adjust tax_heatmap genus and species, pasteurella
tax_heatmap$Genus <- as.character(tax_heatmap$Genus)
tax_heatmap$Species <- as.character(tax_heatmap$Species)

library(circlize)

tax_heatmap <- tax_heatmap[order(rownames(mat_scaled)),]
common_rows <- intersect(rownames(tax_heatmap), colnames(mat_scaled))
tax_heatmap <- tax_heatmap[common_rows, ]
mat_scaled <- t(mat_scaled[,common_rows])
#rownames(tax_heatmap)<- tax_heatmap$Species
rownames(mat_scaled) <-rownames(tax_heatmap)

## Order by stress group
# meta <- meta %>% data.frame %>% arrange(Stress_group)
# mat_scaled <- mat_scaled[,rownames(meta)]

plot <- mat_scaled
genus <- unique(as.character(tax_heatmap$Genus))
#genus_col <- colorRampPalette(my_palette)(length(genus))#
genus_col <- my_palette[1:length(genus)]
names(genus_col) <- genus

pvalue_col_fun = circlize::colorRamp2(c(1,0.1,0.05), c("red", "white", "lightseagreen"))

library(ComplexHeatmap)

ha_row <- HeatmapAnnotation(
  #'Control vs Stress'=anno_simple(-log10(tax_heatmap$p_val),col = pvalue_col_fun, pch = na_if(tax_heatmap$sign,"ns"), gp = gpar(circlize::fontsize(1))),
                            Genus=anno_simple(tax_heatmap$Genus, col = genus_col),
                            which = "row")

ha_row_txt <- rowAnnotation(labels = anno_text(rownames(tax_heatmap), which = "row",gp=gpar(fontsize=10, face= "italic")))




ha_col = HeatmapAnnotation('Stress group'=meta$Stress_group,
                           col = list('Stress group'=c("Stress"=col_fil[2],
                                                  "Control"=col_fil[1]))
                           # , width = max_text_width(unlist(text_list))
                           )



Hist <- ComplexHeatmap::pheatmap(plot, 
                                 cluster_cols = TRUE, cluster_rows = TRUE,
                                 name="Z-score", col=circlize::colorRamp2(c(-2, 0, 2), c("dodgerblue4", "white","deeppink3")),
                                 top_annotation = ha_col,
                                 left_annotation = ha_row,
                                 right_annotation = ha_row_txt,
                                 show_colnames = FALSE, 
                                 show_rownames = FALSE,
                                 heatmap_legend_param = list(legend_direction = "horizontal")
                                 )
Hist

# define the two legend
lgd_genus = Legend(title = "Genus", legend_gp = gpar(fill = genus_col),labels = genus, ncol = 3)

lgd_sig = Legend(title= " ", pch = "*", type = "points", labels = "p < 0.05")


pvalue_col_fun = colorRamp2(c(1,0.1,0.05), c("red", "white", "lightseagreen"))



lgd_pvalue = Legend(title = "p value",
                    col_fun  = pvalue_col_fun,
                    at = c(0, 1, 2),
                    labels = c("1","0.1","0.05"),
                    direction = "vertical")

p_Deseq_heatmap <-draw(Hist,
                       heatmap_legend_list=list(lgd_genus
                                                #lgd_pvalue,
                                                #lgd_sig
                                                ),
                       heatmap_legend_side = "bottom", annotation_legend_side = "bottom") 

p_Deseq_heatmap 

Stress group

Timepoint

Stress group with time point as fixed effect

Genus level

Pheatmap

## [1] "Stress_group"     "Sex_child"        "Education_mother" "Timepoint"

Species level

Time point with stress group as fixed effect

Differential abundance - MaAsLin2

ASV level

Genus level

Species level

Effect size

Dependent and independent effect size

Capscale examines the correlation of each varible independently. Adonis uses dbRDA to quantidy the effect of the most strongest correlating factor, removing it and then examining the remaining effect of the next factor and so forth…

Adjusted for timepoint

Adjusted for infant sex + timepoint

Infant factors

## [1] "Infant_temp_NEG"  "Infant_temp_REG"  "Infant_temp_SUR"  "Infant_weight_w2"
## [5] "Infant_weight_3m" "Timepoint"
## [1] "Infant_temp_NEG"  "Infant_temp_REG"  "Infant_temp_SUR"  "Infant_weight_w2"
## [5] "Infant_weight_3m" "Timepoint"

Cortisol

## [1] "Hair cortisol"                "HM_cortisol_AUC_1"           
## [3] "HM_cortisol_AUC_2"            "Saliva_cortisol_morning_peak"
## [5] "Timepoint"
## [1] "Hair cortisol"                "HM_cortisol_AUC_1"           
## [3] "HM_cortisol_AUC_2"            "Saliva_cortisol_morning_peak"
## [5] "Timepoint"

Metadata auto correlations

Microeco plots

Beta diversity

Time

variable = "Stress_group"


#Calculta beta diversity metrics
meco_dat$cal_betadiv(unifrac = TRUE)
## Accumulate the abundance along the tree branches...
## Compute pairwise distances ...
## Completed!
# create an trans_beta object
# measure parameter must be one of names(dataset$beta_diversity)
t1 <- trans_beta$new(dataset = meco_dat, group = variable, measure = "bray")

#PCoA, PCA and NMDS are available
t1$cal_ordination(ordination = "PCoA")

# t1$res_ordination is the ordination result list
#class(t1$res_ordination)

# plot the PCoA result with confidence ellipse
#t1$plot_ordination(plot_color = variable, plot_shape = variable, plot_type = c("point", "ellipse"))

Within-group distances

# calculate and plot sample distances within groups
t1$cal_group_distance(within_group = TRUE)
# return t1$res_group_distance
# perform Wilcoxon Rank Sum and Signed Rank Tests
t1$cal_group_distance_diff(method = "wilcox")
# plot_group_order parameter can be used to adjust orders in x axis
t1$plot_group_distance(boxplot_add = "mean")

Dispersion

# for the whole comparison and for each paired groups
t1$cal_betadisper()
## The result is stored in object$res_betadisper ...
t1$res_betadisper
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 999
## 
## Response: Distances
##            Df  Sum Sq  Mean Sq      F N.Perm Pr(>F)   
## Groups      1 0.08297 0.082974 7.8283    999  0.007 **
## Residuals 178 1.88668 0.010599                        
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Pairwise comparisons:
## (Observed p-value below diagonal, permuted p-value above diagonal)
##           Control Stress
## Control            0.008
## Stress  0.0057101

Timepoint

variable = "Timepoint"
# create an trans_beta object
# measure parameter must be one of names(dataset$beta_diversity)
t1 <- trans_beta$new(dataset = meco_dat, group = variable, measure = "bray")

#PCoA, PCA and NMDS are available
t1$cal_ordination(ordination = "PCoA")

# t1$res_ordination is the ordination result list
#class(t1$res_ordination)

# plot the PCoA result with confidence ellipse
#t1$plot_ordination(plot_color = variable, plot_shape = variable, plot_type = c("point", "ellipse"))

Within-group distances

# calculate and plot sample distances within groups
t1$cal_group_distance(within_group = TRUE)
# return t1$res_group_distance
# perform Wilcoxon Rank Sum and Signed Rank Tests
t1$cal_group_distance_diff(method = "wilcox")
# plot_group_order parameter can be used to adjust orders in x axis
t1$plot_group_distance(boxplot_add = "mean")

Dispersion

# for the whole comparison and for each paired groups
t1$cal_betadisper()
## The result is stored in object$res_betadisper ...
t1$res_betadisper
## 
## Permutation test for homogeneity of multivariate dispersions
## Permutation: free
## Number of permutations: 999
## 
## Response: Distances
##            Df  Sum Sq  Mean Sq     F N.Perm Pr(>F)  
## Groups      1 0.07593 0.075928 7.179    999  0.013 *
## Residuals 178 1.88262 0.010577                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Pairwise comparisons:
## (Observed p-value below diagonal, permuted p-value above diagonal)
##           p10   p24
## p10           0.012
## p24 0.0080681

Explainable class

Seclect variables

#env <- select(meco_dat$sample_table,all_of(effect.size.variables)) %>%
#  mutate(Stress_group = as.numeric(as.character(Stress_group))) %>%
#  select(-c("Batch","AB.infant")) %>%
#  select(where(is.numeric)) %>%
#  drop_na(Gestational.age) %>%
#  drop_na() %>%
#  select_if(~ !any(is.na(.)))

env <- meco_dat$sample_table %>%
  dplyr::select(key.vars) %>%
  dplyr::select(-Timepoint) %>%
 drop_na() %>%
  #tidyr::drop_na() %>% #Drop any rows with NAs
  dplyr::mutate_if(is.character, as.factor)

#Fix environmental variable names
colnames(env) <- colnames(env) %>% gsub("_"," ",.)

str(env)
## 'data.frame':    173 obs. of  6 variables:
##  $ Stress group     : Factor w/ 2 levels "Control","Stress": 1 1 1 1 1 1 1 1 1 1 ...
##  $ Sex child        : int  0 1 0 1 0 0 1 0 1 0 ...
##  $ PSS stress score : int  6 8 17 13 16 18 16 10 7 8 ...
##  $ LSCr stress score: int  12 5 15 0 18 5 3 17 6 7 ...
##  $ Education mother : int  8 9 7 8 8 9 7 8 8 8 ...
##  $ BMI mother       : num  23.9 21.9 25.9 22.3 20.8 ...
colnames(env)
## [1] "Stress group"      "Sex child"         "PSS stress score" 
## [4] "LSCr stress score" "Education mother"  "BMI mother"

Creating trans_env object

env$`Sex child` <- env$`Sex child` %>% recode("0"="Female","1"="Male")

t1 <- trans_env$new(dataset = meco_dat,
                    add_data = env)

RDA

Genus

# use Genus
t1$cal_ordination(method = "RDA", taxa_level = "Genus")
# As the main results of RDA are related with the projection and angles between different arrows,
# we adjust the length of the arrow to show them clearly using several parameters.
t1$trans_ordination(show_taxa = 10, adjust_arrow_length = TRUE,
                    min_perc_env = 0.2,
                    max_perc_env = 0.5,
                    min_perc_tax = 1.5,
                    max_perc_tax = 2.5
                    )
# t1$res_rda_trans is the transformed result for plot

rda.group <- t1$plot_ordination(plot_color = "Stress_group",
                                plot_type = c("point"),
                                env_text_size = 4,
                   taxa_text_size = 4,
                   taxa_text_color="darkred",
                   taxa_arrow_color="darkred",
                   point_alpha=0.2,
                   taxa_nudge_x = c(0,0,0,-150,0,0,0,0,0,0),
                   taxa_nudge_y = c(0,100,300,0,-200,-100,-100,-200,2,0)) + 
  theme_classic() + 
  theme(plot.title = element_text(size = 12, face = "bold",hjust = 0.5),
        strip.background = element_blank(),
        strip.text.x = element_blank()
        #legend.position = "none"
        ) +
  labs(color="Stress group",fill="") +
  scale_fill_discrete(guide = FALSE)

rda.group

Species environmental factors

The correlations between environmental variables and taxa are important in analyzing and inferring the factors affecting community structure. Let’s first perform a correlation heatmap using relative abundance data at Genus level with the cal_cor function. The parameter p_adjust_type can control the p value adjustment type.

env <- meco_dat$sample_table %>% dplyr::select(key.vars.cortisol)

#env <- meco_dat$sample_table %>% dplyr::select(key.vars.inf)
#env <- meco_dat$sample_table %>% dplyr::select(key.vars)

t1 <- trans_env$new(dataset = meco_dat, add_data = env)

Genus vs cortisol measures

# 'p_adjust_type = "Env"' means p adjustment is performed for each environmental variable separately.
t1$cal_cor(use_data = "Genus", p_adjust_method = "fdr", p_adjust_type = "Env")

Then, we can plot the correlation results using plot_cor function.

# default ggplot2 method with clustering
t1$plot_cor(cluster_ggplot = "both")

There are too many genera. We can use the filter_feature parameter in plot_cor to filter some taxa that do not have any significance < 0.001.

# filter genera that donot have at least one ** or ***
t1$plot_cor(filter_feature = c(""),cluster_ggplot = "both")

Split by time point

# 'p_adjust_type = "Env"' means p adjustment is performed for each environmental variable separately.
t1$cal_cor(use_data = "Genus", p_adjust_method = "fdr", p_adjust_type = "Env",by_group = "Day")

There are too many genera. We can use the filter_feature parameter in plot_cor to filter some taxa that do not have any significance < 0.001.

# filter genera that donot have at least one ** or ***
t1$plot_cor(filter_feature = c(""),cluster_ggplot = "both",pheatmap = FALSE)

pearson.cortisol.day <- t1$plot_cor(filter_feature = c(""),cluster_ggplot = "both",pheatmap = FALSE) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Sometimes, if the user wants to do the correlation analysis between the environmental factors and some important taxa detected in the biomarker analysis, please use other_taxa parameter in cal_cor function.

# first create trans_diff object as a demonstration
t2 <- trans_diff$new(dataset = meco_dat, method = "rf", group = "Stress_group", taxa_level = "Genus",p_adjust_method = "none")
# then create trans_env object
t1 <- trans_env$new(dataset = meco_dat, add_data = env)
# use other_taxa to select taxa you need
t1$cal_cor(use_data = "other", p_adjust_method = "fdr", other_taxa = t2$res_diff$Taxa)
t1$plot_cor()

The pheatmap method is also available. Note that, besides the color_vector parameter, color_palette can also be used to control color palette with customized colors.

# clustering heatmap; require pheatmap package
# Let's take another color pallete
t1$plot_cor(pheatmap = TRUE, color_palette = rev(RColorBrewer::brewer.pal(n = 9, name = "RdYlBu")))

## TableGrob (5 x 6) "layout": 6 grobs
##   z     cells      name                         grob
## 1 1 (2-2,3-3)  col_tree polyline[GRID.polyline.4202]
## 2 2 (4-4,1-1)  row_tree polyline[GRID.polyline.4203]
## 3 3 (4-4,3-3)    matrix       gTree[GRID.gTree.4206]
## 4 4 (5-5,3-3) col_names         text[GRID.text.4207]
## 5 5 (4-4,4-4) row_names         text[GRID.text.4208]
## 6 6 (3-5,5-5)    legend       gTree[GRID.gTree.4211]

Sometimes, if it is needed to study the correlations between environmental variables and taxa for different groups, by_group parameter can be used for this goal.

# calculate correlations for different groups using parameter by_group
t1$cal_cor(by_group = "Timepoint",  p_adjust_method = "fdr")
# return t1$res_cor
t1$plot_cor(filter_feature = c("", "*")) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Functional predictions

Ecological researchers are usually interested in the the funtional profiles of microbial communities, because functional or metabolic data is powerful to explain the structure and dynamics of microbial communities. As metagenomic sequencing is complicated and expensive, using amplicon sequencing data to predict functional profiles is an alternative choice. Several software are often used for this goal, such as PICRUSt (Langille et al. 2013), Tax4Fun (Aßhauer et al. 2015) and FAPROTAX (Stilianos Louca et al. 2016; S. Louca, Parfrey, and Doebeli 2016). These tools are great to be used for the prediction of functional profiles based on the prokaryotic communities from sequencing results. In addition, it is also important to obtain the traits or functions for each taxa, not just the whole profile of communities. FAPROTAX database is a collection of the traits and functions of prokaryotes based on the known research results published in books and literatures. We match the taxonomic information of prokaryotes against this database to predict the traits of prokaryotes on biogeochemical roles. The NJC19 database (Lim et al. 2020) is also available for animal-associated prokaryotic data, such as human gut microbiota. We also implement the FUNGuild (Nguyen et al. 2016) and FungalTraits (Põlme et al. 2020) databases to predict the fungal traits. The idea identifying prokaryotic traits and functional redundancy was initially inspired by our another study (Liu et al. 2022).

We first identify/predict traits of taxa with the prokaryotic example data.

# create object of trans_func
t2 <- trans_func$new(meco_dat)
# mapping the taxonomy to the database
# this can recognize prokaryotes or fungi automatically if the names of taxonomic levels are standard.
# for fungi example, see https://chiliubio.github.io/microeco_tutorial/other-dataset.html#fungi-data
# default database for prokaryotes is FAPROTAX database
t2$cal_spe_func(prok_database = "FAPROTAX")

The percentages of the OTUs having the same trait can reflect the functional redundancy of this function in the community.

# calculate the percentages for communities
# here do not consider the abundance
t2$cal_spe_func_perc(abundance_weighted = FALSE)

Then we also take an example to show the percentages of the OTUs for each trait in network modules.

# construct a network for the example
network <- trans_network$new(dataset = meco_dat, cal_cor = "base", taxa_level = "OTU", filter_thres = 0.0001, cor_method = "spearman")
network$cal_network(p_thres = 0.01, COR_cut = 0.7)
network$cal_module()
# convert module info to microtable object
meco_module <- network$trans_comm(use_col = "module")
meco_module_func <- trans_func$new(meco_module)
meco_module_func$cal_spe_func(prok_database = "FAPROTAX")
meco_module_func$cal_spe_func_perc(abundance_weighted = FALSE)
meco_module_func$plot_spe_func_perc(order_x = paste0("M", 1:10))

Environmental factors vs functional predictions

# then we try to correlate the res_spe_func_perc of communities to environmental variables
t3 <- trans_env$new(dataset = meco_dat, add_data = env)
t3$cal_cor(add_abund_table = t2$res_spe_func_perc, cor_method = "spearman")
t3$plot_cor(pheatmap = TRUE
            #filter_feature = c("")
            )

## TableGrob (5 x 6) "layout": 6 grobs
##   z     cells      name                         grob
## 1 1 (2-2,3-3)  col_tree polyline[GRID.polyline.4419]
## 2 2 (4-4,1-1)  row_tree polyline[GRID.polyline.4420]
## 3 3 (4-4,3-3)    matrix       gTree[GRID.gTree.4423]
## 4 4 (5-5,3-3) col_names         text[GRID.text.4424]
## 5 5 (4-4,4-4) row_names         text[GRID.text.4425]
## 6 6 (3-5,5-5)    legend       gTree[GRID.gTree.4428]

Arrange figures

Figure 3 - Barplots, alpha,beta div and differential abundance by stress groups

Figure S1 - Barplots, alpha beta div by timepoints

Figure S2 - Relative abundance by stress group by time point

Figure 3 - Microbial interactions - run in “AMS_MicroEcoAnalyis.Rmd”

Outputs saved, and figure manually arranged in Powerpoint

Figure S3 - Infant outcomes effect size

Figure 5 - Clinical factors and microbiome composition

Session info

## R version 4.2.1 (2022-06-23 ucrt)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19045)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=Danish_Denmark.utf8  LC_CTYPE=Danish_Denmark.utf8   
## [3] LC_MONETARY=Danish_Denmark.utf8 LC_NUMERIC=C                   
## [5] LC_TIME=Danish_Denmark.utf8    
## 
## attached base packages:
## [1] stats4    grid      stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] cowplot_1.1.3                  igraph_1.6.0                  
##  [3] pheatmap_1.0.12                ComplexHeatmap_2.12.1         
##  [5] circlize_0.4.15                DESeq2_1.36.0                 
##  [7] rabuplot_0.0.1.08              beemStatic_0.0.1              
##  [9] SpiecEasi_1.1.2                chorddiag_0.1.3               
## [11] microViz_0.10.8                ampvis2_2.8.6                 
## [13] Maaslin2_1.10.0                ggtree_3.4.4                  
## [15] decontam_1.16.0                miaViz_1.4.0                  
## [17] ggraph_2.1.0                   mia_1.4.0                     
## [19] MultiAssayExperiment_1.22.0    TreeSummarizedExperiment_2.4.0
## [21] Biostrings_2.64.1              XVector_0.36.0                
## [23] SingleCellExperiment_1.18.1    SummarizedExperiment_1.26.1   
## [25] Biobase_2.56.0                 GenomicRanges_1.48.0          
## [27] GenomeInfoDb_1.32.4            IRanges_2.30.1                
## [29] S4Vectors_0.34.0               BiocGenerics_0.42.0           
## [31] MatrixGenerics_1.8.1           matrixStats_1.2.0             
## [33] ANCOMBC_1.6.4                  phyloseq_1.40.0               
## [35] here_1.0.1                     GUniFrac_1.8                  
## [37] microeco_1.4.0                 zscorer_0.3.1                 
## [39] VennDiagram_1.7.3              futile.logger_1.4.3           
## [41] ggalluvial_0.12.5              UpSetR_1.4.0                  
## [43] RColorBrewer_1.1-3             ggsci_3.0.0                   
## [45] ggpubr_0.6.0                   rstatix_0.7.2                 
## [47] vegan_2.6-4                    lattice_0.22-5                
## [49] permute_0.9-7                  lubridate_1.9.3               
## [51] forcats_1.0.0                  stringr_1.5.1                 
## [53] dplyr_1.1.4                    purrr_1.0.2                   
## [55] readr_2.1.5                    tidyr_1.3.1                   
## [57] tibble_3.2.1                   ggplot2_3.4.4                 
## [59] tidyverse_2.0.0                ggprism_1.0.4                 
## [61] BiocManager_1.30.22            devtools_2.4.5                
## [63] usethis_2.2.2                  patchwork_1.2.0               
## [65] DT_0.31                        ggtext_0.1.2                  
## [67] tidytext_0.4.1                
## 
## loaded via a namespace (and not attached):
##   [1] metagMisc_0.0.4             graphlayouts_1.1.0         
##   [3] vctrs_0.6.5                 expm_0.999-9               
##   [5] mgcv_1.9-1                  gmp_0.7-4                  
##   [7] rmutil_1.1.10               blob_1.2.4                 
##   [9] survival_3.5-7              later_1.3.2                
##  [11] nloptr_2.0.3                DBI_1.2.1                  
##  [13] zlibbioc_1.42.0             fBasics_4032.96            
##  [15] timeSeries_4032.109         GlobalOptions_0.1.2        
##  [17] htmlwidgets_1.6.4           mvtnorm_1.2-4              
##  [19] inline_0.3.19               parallel_4.2.1             
##  [21] scater_1.24.0               irlba_2.3.5.1              
##  [23] markdown_1.12               DEoptimR_1.1-3             
##  [25] tidygraph_1.3.0             Rcpp_1.0.12                
##  [27] KernSmooth_2.23-22          promises_1.2.1             
##  [29] DelayedArray_0.22.0         limma_3.52.4               
##  [31] pkgload_1.3.4               magick_2.8.2               
##  [33] Hmisc_5.1-1                 fs_1.6.3                   
##  [35] textshaping_0.3.7           png_0.1-8                  
##  [37] digest_0.6.34               glmnet_4.1-8               
##  [39] janeaustenr_1.0.0           pkgconfig_2.0.3            
##  [41] ggnewscale_0.4.9            DelayedMatrixStats_1.18.2  
##  [43] ggbeeswarm_0.7.2            estimability_1.4.1         
##  [45] iterators_1.0.14            minqa_1.2.6                
##  [47] biglm_0.9-2.1               beeswarm_0.4.0             
##  [49] GetoptLong_1.0.5            selectiveInference_1.2.5   
##  [51] xfun_0.41                   bslib_0.6.1                
##  [53] zoo_1.8-12                  tidyselect_1.2.0           
##  [55] reshape2_1.4.4              pcaPP_2.0-4                
##  [57] viridisLite_0.4.2           pkgbuild_1.4.3             
##  [59] rlang_1.1.3                 jquerylib_0.1.4            
##  [61] Rmpfr_0.9-5                 glue_1.7.0                 
##  [63] lambda.r_1.2.4              emmeans_1.10.0             
##  [65] ggsignif_0.6.4              labeling_0.4.3             
##  [67] httpuv_1.6.14               biomformat_1.24.0          
##  [69] class_7.3-22                BiocNeighbors_1.14.0       
##  [71] TH.data_1.1-2               tokenizers_0.3.0           
##  [73] Wrench_1.14.0               annotate_1.74.0            
##  [75] jsonlite_1.8.8              systemfonts_1.0.5          
##  [77] bit_4.0.5                   mime_0.12                  
##  [79] gridExtra_2.3               gplots_3.1.3               
##  [81] Exact_3.2                   stringi_1.8.3              
##  [83] gsl_2.1-8                   rbibutils_2.2.16           
##  [85] yulab.utils_0.1.4           bitops_1.0-7               
##  [87] cli_3.6.2                   Rdpack_2.6                 
##  [89] rhdf5filters_1.8.0          RSQLite_2.3.5              
##  [91] randomForest_4.7-1.1        spatial_7.3-17             
##  [93] data.table_1.14.10          energy_1.7-11              
##  [95] timechange_0.3.0            rstudioapi_0.15.0          
##  [97] microbiome_1.18.0           CVXR_1.0-11                
##  [99] nlme_3.1-164                locfit_1.5-9.8             
## [101] DECIPHER_2.24.0             SnowballC_0.7.1            
## [103] miniUI_0.1.1.1              gridGraphics_0.5-1         
## [105] urlchecker_1.0.1            stable_1.1.6               
## [107] optparse_1.7.4              sessioninfo_1.2.2          
## [109] readxl_1.4.3                lifecycle_1.0.4            
## [111] timeDate_4032.109           commonmark_1.9.1           
## [113] munsell_0.5.0               cellranger_1.1.0           
## [115] statip_0.2.3                caTools_1.18.2             
## [117] codetools_0.2-19            coda_0.19-4                
## [119] vipor_0.4.7                 htmlTable_2.4.2            
## [121] xtable_1.8-4                formatR_1.14               
## [123] lpsymphony_1.24.0           abind_1.4-5                
## [125] farver_2.1.1                pulsar_0.3.11              
## [127] aplot_0.2.2                 futile.options_1.0.1       
## [129] profvis_0.3.8               cluster_2.1.6              
## [131] Matrix_1.6-5                tidytree_0.4.6             
## [133] ellipsis_0.3.2              metagenomeSeq_1.38.0       
## [135] adaptMCMC_1.5               multtest_2.52.0            
## [137] remotes_2.4.2.1             lmerTest_3.1-3             
## [139] getopt_1.20.4               htmltools_0.5.7            
## [141] yaml_2.3.8                  utf8_1.2.4                 
## [143] plotly_4.10.4               XML_3.99-0.16.1            
## [145] e1071_1.7-14                foreign_0.8-86             
## [147] withr_3.0.0                 scuttle_1.6.3              
## [149] BiocParallel_1.30.4         bit64_4.0.5                
## [151] rngtools_1.5.2              doRNG_1.8.6                
## [153] rootSolve_1.8.2.4           multcomp_1.4-25            
## [155] foreach_1.5.2               robustbase_0.99-2          
## [157] ragg_1.2.7                  rsvd_1.0.5                 
## [159] ScaledMatrix_1.4.1          memoise_2.0.1              
## [161] evaluate_0.23               VGAM_1.1-9                 
## [163] geneplotter_1.74.0          tzdb_0.4.0                 
## [165] lmom_3.0                    fansi_1.0.6                
## [167] highr_0.10                  checkmate_2.3.1            
## [169] cachem_1.0.8                rjson_0.2.21               
## [171] ggrepel_0.9.5               ade4_1.7-22                
## [173] clue_0.3-65                 rprojroot_2.0.4            
## [175] tools_4.2.1                 stabledist_0.7-1           
## [177] sass_0.4.8                  sandwich_3.1-0             
## [179] magrittr_2.0.3              RCurl_1.98-1.14            
## [181] proxy_0.4-27                car_3.1-2                  
## [183] ape_5.7-1                   ggplotify_0.1.2            
## [185] xml2_1.3.6                  httr_1.4.7                 
## [187] rmarkdown_2.25              boot_1.3-28.1              
## [189] R6_2.5.1                    Rhdf5lib_1.18.2            
## [191] nnet_7.3-19                 KEGGREST_1.36.3            
## [193] DirichletMultinomial_1.38.0 genefilter_1.78.0          
## [195] treeio_1.20.2               gtools_3.9.5               
## [197] shape_1.4.6                 statmod_1.5.0              
## [199] beachmat_2.12.0             BiocSingular_1.12.0        
## [201] rhdf5_2.40.0                splines_4.2.1              
## [203] carData_3.0-5               ggfun_0.1.4                
## [205] colorspace_2.1-0            generics_0.1.3             
## [207] base64enc_0.1-3             gridtext_0.1.5             
## [209] pillar_1.9.0                tweenr_2.0.2               
## [211] GenomeInfoDbData_1.2.8      plyr_1.8.9                 
## [213] gtable_0.3.4                knitr_1.45                 
## [215] fastmap_1.1.1               Cairo_1.6-2                
## [217] modeest_2.4.0               doParallel_1.0.17          
## [219] AnnotationDbi_1.58.0        broom_1.0.5                
## [221] scales_1.3.0                huge_1.3.5                 
## [223] backports_1.4.1             EnhancedVolcano_1.14.0     
## [225] file2meco_0.7.0             lme4_1.1-35.1              
## [227] gld_2.6.6                   hms_1.1.3                  
## [229] ggforce_0.4.1               Rtsne_0.17                 
## [231] shiny_1.8.0                 polyclip_1.10-6            
## [233] numDeriv_2016.8-1.1         DescTools_0.99.53          
## [235] lazyeval_0.2.2              Formula_1.2-5              
## [237] crayon_1.5.2                MASS_7.3-60.0.1            
## [239] sparseMatrixStats_1.8.0     viridis_0.6.5              
## [241] rpart_4.1.23                compiler_4.2.1             
## [243] intervals_0.15.4
LS0tDQp0aXRsZTogIjE2UyBhbmFseXNpcyBBTVMgc3RyZXNzIGFuZCBtb3RoZXJzIG1pbGsiDQphdXRob3I6ICJSYXNtdXMgUmllbWVyIEpha29ic2VuIg0KZGF0ZTogImByIFN5cy50aW1lKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnMycNCmxpbmstY2l0YXRpb25zOiB5ZXMNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KI0xvYWQgcGFja2FnZXMNCnNvdXJjZSgicGFja2FnZV9sb2FkX2luc3RhbGwuUiIpDQoNCiNDb3Vsb3VyIHBhbGxldHRlcw0KIyBjb2xfZmlsIDwtIHBhbF9qY28oImRlZmF1bHQiKSgxMCkNCiMgY29sX3NjYWxlIDwtIHNjYWxlX2NvbG9yX2pjbygpDQpjb2xfZmlsIDwtIGJyZXdlci5wYWwoMTAsICJEYXJrMiIpI3BhbF9qY28oImRlZmF1bHQiKSgxMCkNCg0KY29sX3NjYWxlIDwtIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKHBhbGV0dGUgPSAiRGFyazIiKQ0KDQp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYyhiYXNlX2ZhbWlseSA9ICJzYW5zIikpICNzYW5zID0gVFQgQXJpYWwsIG1vbm8gPSBUVCBjb3VyaWVyIG5ldywgc2VyaWYgPSBUVCBUaW1lcyBuZXcgcm9tYW4gIA0KDQpzb3VyY2UoInV0aWxzLlIiKQ0KDQojTG9hZCBwaHlsb3NlcSBvYmplY3RzDQoNCnBzLmN1ciA8LSByZWFkUkRTKCJwcy4yMDIwXzA1X0FNUy4yMDIwLTAzLTMxLmN1cmF0ZWQuUkRTIikNCnBzLmN1cg0KcHM8LXBzLmN1cg0KDQogYXN2X2xhYmVsIDwtIGZ1bmN0aW9uKHBzLCBzcGVjaWVzPVQsIGNvbGxhcHNlX3NwZWNpZXM9Mil7DQogIGlmIChzcGVjaWVzPT1UKXtwc0B0YXhfdGFibGVbLCJTcGVjaWVzIl1bbGFwcGx5KHN0cnNwbGl0KHBzQHRheF90YWJsZVssN10sIi8iKSwgbGVuZ3RoKT5jb2xsYXBzZV9zcGVjaWVzXSA8LSAiQW1iaWdvdXMifQ0KICBsYWJlbD10YXhhX25hbWVzKHBzKQ0KICBsYWJlbFshaXMubmEocHNAdGF4X3RhYmxlWywxXSldIDwtIHBhc3RlMCgia18iLHBzQHRheF90YWJsZVssMV0pWyFpcy5uYShwc0B0YXhfdGFibGVbLDFdKV0NCiAgbGFiZWxbIWlzLm5hKHBzQHRheF90YWJsZVssMl0pXSA8LSBwYXN0ZTAoInBfIixwc0B0YXhfdGFibGVbLDJdKVshaXMubmEocHNAdGF4X3RhYmxlWywyXSldDQogIGxhYmVsWyFpcy5uYShwc0B0YXhfdGFibGVbLDNdKV0gPC0gcGFzdGUwKCJjXyIscHNAdGF4X3RhYmxlWywzXSlbIWlzLm5hKHBzQHRheF90YWJsZVssM10pXQ0KICBsYWJlbFshaXMubmEocHNAdGF4X3RhYmxlWyw0XSldIDwtIHBhc3RlMCgib18iLHBzQHRheF90YWJsZVssNF0pWyFpcy5uYShwc0B0YXhfdGFibGVbLDRdKV0NCiAgbGFiZWxbIWlzLm5hKHBzQHRheF90YWJsZVssNV0pXSA8LSBwYXN0ZTAoImZfIixwc0B0YXhfdGFibGVbLDVdKVshaXMubmEocHNAdGF4X3RhYmxlWyw1XSldDQogIGxhYmVsWyFpcy5uYShwc0B0YXhfdGFibGVbLDZdKV0gPC0gcGFzdGUwKCJnXyIscHNAdGF4X3RhYmxlWyw2XSlbIWlzLm5hKHBzQHRheF90YWJsZVssNl0pXQ0KICBpZiAoc3BlY2llcz09VCl7DQogICAgbGFiZWxbIWlzLm5hKHBzQHRheF90YWJsZVssN10pXSA8LSBwYXN0ZTAoInNfIixwc0B0YXhfdGFibGVbLDZdLCJfIiwgcHNAdGF4X3RhYmxlWyw3XSlbIWlzLm5hKHBzQHRheF90YWJsZVssN10pXX0NCiAgbGFiZWwgPC0gbWFrZS51bmlxdWUobGFiZWwpDQogIHJldHVybihsYWJlbCkNCn0NCg0KdGF4YV9uYW1lcyhwcy5jdXIpIDwtIGFzdl9sYWJlbChwcy5jdXIpDQoNCiNSZW5hbWUgYW1iaWdvdXMgc3BlY2llcyBuYW1lcw0KcmVuYW1lX2VudHJpZXMgPC0gZnVuY3Rpb24oeCkgew0KICBpZl9lbHNlKHN0cl9jb3VudCh4LCAiLyIpID4gMSwgIkFtYmlnb3VzIiwgeCkNCn0NCg0KdGF4YS5uYW1lcyA8LSB0YXhhX25hbWVzKHBzLmN1cikNCg0KdGF4Lm5vbmFtYiA8LSBwcy5jdXJAdGF4X3RhYmxlICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIG11dGF0ZShhY3Jvc3MoU3BlY2llcywgcmVuYW1lX2VudHJpZXMpKQ0KDQpyb3cubmFtZXModGF4Lm5vbmFtYikgPC0gdGF4YS5uYW1lcw0KaGVhZCh0YXgubm9uYW1iKQ0KDQp0YXhfdGFibGUocHMuY3VyKSA8LSBhcyh0YXgubm9uYW1iLCJtYXRyaXgiKQ0KDQojVXNlIGN1cmF0ZWQsIEFTViByZWxhYmJlbGVkIE9UVSB0YWJsZSBmb3IgYW5hbHlzaXMNClBTQiA8LSBwcy5jdXINCmBgYA0KDQojIFByZS1wcm9jZXNzaW5nDQoNCiMjIE1lcmdlIG1ldGFkYXRhDQoNCk9ubHkgcnVuIGZvciBvcmlnaW5hbCBub24tcmFuZG9taXplZCBtZXRhZGF0YQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZyA9IEZ9DQptZXRhLm1pY3JvYmlvbWUgPC0gcmVhZHhsOjpyZWFkX3hsc3goIjEuIE1ldGFkYXRhIC0gTWljcm9iaW9tZSBFeGNlbCBjaGFyYWN0ZXJpc3RpY3MueGxzeCIpDQptZXRhLjI0aGZvb2QgPC0gcmVhZHhsOjpyZWFkX3hsc3goIjMuIE1ldGFkYXRhIC0gTWljcm9iaW9tZSBFeGNlbCAyNGggZm9vZCBpbnRha2UueGxzeCIpDQptZXRhLmNvcnRpc29sIDwtIHJlYWR4bDo6cmVhZF94bHN4KCJDb3J0aXNvbF92YXJpYWJlbGVuX21pY3JvYmlvbWUueGxzeCIpDQojbWV0YS5mZnFmb29kIDwtIHJlYWR4bDo6cmVhZF94bHN4KCI0LiBNZXRhZGF0YSAtIE1pY3JvYmlvbWUgRXhjZWwgRkZRIGZvb2QgaW50YWtlLnhsc3giKQ0KbWV0YS5vdXRjb21lcyA8LSByZWFkeGw6OnJlYWRfeGxzeCgiSW5mYW50IG91dGNvbWVzLnhsc3giKSAlPiUgZHBseXI6OnJlbmFtZShBTVNfSUQgPSBTdWJqZWN0X0lEKQ0KDQoNCm1ldGEuZGF0IDwtIGRhdGEuZnJhbWUoc2FtcGxlX2RhdGEoUFNCKSkNCm1ldGEuZGF0JElEIDwtIG1ldGEuZGF0JEV4dF9JRA0KDQptZXRhIDwtIGRwbHlyOjpsZWZ0X2pvaW4obWV0YS5kYXQsbWV0YS5taWNyb2Jpb21lLGJ5PSJJRCIpDQptZXRhIDwtIGRwbHlyOjpsZWZ0X2pvaW4obWV0YSxtZXRhLmNvcnRpc29sLGJ5PSJJRCIpDQptZXRhIDwtIGRwbHlyOjpsZWZ0X2pvaW4obWV0YSxtZXRhLjI0aGZvb2QsYnk9IklEIikNCg0KbWV0YSA8LSBtZXRhICU+JSB0aWR5cjo6c2VwYXJhdGVfd2lkZXJfcmVnZXgoSW50X0lELCBjKEFNU19JRCA9ICIuKiIsICJfIiwgVGltZWNvZGUgPSAiLioiKSxjb2xzX3JlbW92ZT1GQUxTRSkjU3BsaXQgaW50ZXJuYWwgaWQgdG8gc2VwYXJhdGUgaWQgYW5kIHRpbWVwaW50IGNvZGUNCg0KbWV0YSA8LSBkcGx5cjo6bGVmdF9qb2luKG1ldGEsbWV0YS5vdXRjb21lcyxieT0iQU1TX0lEIixrZWVwPUZBTFNFKSAjRG8gbm90IGtlZXAgbm9uLW1hdGNoZWQgSURzIGFzIHRoZXNlIGFyZSBmb3IgZXhjbHVkZWQgaW5mYW50cw0KI21ldGEgPC0gZHBseXI6OmxlZnRfam9pbihtZXRhLG1ldGEuZmZxZm9vZCxieT0iSUQiKQ0KDQptZXRhIDwtIHR5cGUuY29udmVydChtZXRhKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQoNCnJvd25hbWVzKG1ldGEpIDwtIHJvd25hbWVzKG1ldGEuZGF0KQ0KDQpzYW1wbGVfZGF0YShQU0IpIDwtIG1ldGENCg0Kc2F2ZVJEUyhQU0IsIkFNU19waHlsb3NlcS5SRFMiKQ0KYGBgDQoNCkFsbCBtZXRhZGF0YSBjb2x1bW5zOg0KDQpgYGB7cn0NCnNvcnQoY29sbmFtZXMobWV0YSkpDQpgYGANCg0KIyMgTG9hZCByYW5kb21pemVkIG1ldGFkYXQNCg0KYGBge3J9DQpQU0IgPC0gcmVhZFJEUygiQU1TX3BoeWxvc2VxLlJEUyIpDQojcmVhZFJEUygiQU1TX3BoeWxvc2VxX3JhbmRvbWl6ZWQuUkRTIikNCmBgYA0KDQoNCiMjIFJlbW92ZSBBU1YgZmFzdGEgc2VxdWVuY2UgY29sdW1uDQoNCmBgYHtyLCBtZXNzYWdlID0gRn0NClBTQkB0YXhfdGFibGUgPC0gdGF4X3RhYmxlKFBTQilbLDE6N10NCmBgYA0KDQojIEZvcm1hdCBtZXRhZGF0YQ0KDQojIyBGb3JtYXQgc3RyZXNzIGdyb3VwIGNvbHVtbg0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBGLCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQpQU0JAc2FtX2RhdGEkU3R1ZHlfZ3JvdXAgPC0gYXMuZmFjdG9yKFBTQkBzYW1fZGF0YSRTdHVkeV9ncm91cCkNCg0KUFNCQHNhbV9kYXRhJFN0cmVzc19ncm91cCA8LSBQU0JAc2FtX2RhdGEkU3R1ZHlfZ3JvdXAgJT4lIHJlY29kZSgiMSI9IkNvbnRyb2wiLCIyIj0iU3RyZXNzIikNCg0KUFNCQHNhbV9kYXRhJERheSA8LSBQU0JAc2FtX2RhdGEkVGltZXBvaW50ICU+JSByZWNvZGUoInAxMCI9IkRheSAxMCIsInAyNCI9IkRheSAyNCIpDQpgYGANCg0KIyMgUmVuYW1lIGdlbmRlciB0byBzZXgNCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gRiwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQ0KUFNCQHNhbV9kYXRhJFNleF9jaGlsZCA8LSBQU0JAc2FtX2RhdGEkR2VuZGVyX2NoaWxkDQpgYGANCg0KIyMgQ2FsY3VsYXRlIFdIWiBzY29yZXMgLSBub3QgZG9uZSB5ZXQNCg0KYGBge3IsIGV2YWwgPSBGfQ0KDQoNCm1ldGEuZGF0JGBXZWlnaHQgbW9udGggMWAgPC0gYXMubnVtZXJpYyhtZXRhLmRhdCRgV2VpZ2h0IG1vbnRoIDFgKQ0KbWV0YS5kYXQkYFdlaWdodCBtb250aCA2YCA8LSBhcy5udW1lcmljKG1ldGEuZGF0JGBXZWlnaHQgbW9udGggNmApDQoNCm1ldGEuZGF0JGBIZWlnaHQgbW9udGggMWAgPC0gYXMubnVtZXJpYyhtZXRhLmRhdCRgSGVpZ2h0IG1vbnRoIDFgKQ0KbWV0YS5kYXQkYEhlaWdodCBtb250aCA2YCA8LSBhcy5udW1lcmljKG1ldGEuZGF0JGBIZWlnaHQgbW9udGggNmApDQoNCm1ldGEuZGF0JGAzMGRheXNgIDwtIDMwDQptZXRhLmRhdCRgMTgwZGF5c2AgPC0gMTgwDQoNCnN2eSA8LSBhZGRXR1NSKGRhdGEgPSBhbnRocm8zLCBzZXggPSAic2V4IiwgZmlyc3RQYXJ0ID0gIndlaWdodCIsDQogICAgICAgICAgICAgICBzZWNvbmRQYXJ0ID0gImhlaWdodCIsIGluZGV4ID0gIndmaCIpDQojIFdlaWdodCBmb3IgaGVpZ2h0DQptZXRhLmRhdCA8LSBhZGRXR1NSKGRhdGEgPSBtZXRhLmRhdCwgc2V4ID0gIkluZmFudCBzZXgiLCBmaXJzdFBhcnQgPSAiV2VpZ2h0IG1vbnRoIDEiLA0KICAgICAgICAgICAgICAgc2Vjb25kUGFydCA9ICJIZWlnaHQgbW9udGggMSIsIGluZGV4ID0gIndmbCIsIG91dHB1dCA9ICJ3aHouMW0iKQ0KDQptZXRhLmRhdCA8LSBhZGRXR1NSKGRhdGEgPSBtZXRhLmRhdCwgc2V4ID0gIkluZmFudCBzZXgiLCBmaXJzdFBhcnQgPSAiV2VpZ2h0IG1vbnRoIDYiLA0KICAgICAgICAgICAgICAgc2Vjb25kUGFydCA9ICJIZWlnaHQgbW9udGggNiIsIGluZGV4ID0gIndmbCIsIG91dHB1dCA9ICJ3aHouNm0iKQ0KDQptZXRhLmRhdCRkZWx0YS53aHogPC0gbWV0YS5kYXQkd2h6LjZtIC0gbWV0YS5kYXQkd2h6LjFtDQoNCiMgSGVpZ2h0IGZvciBhZ2UNCm1ldGEuZGF0IDwtIGFkZFdHU1IoZGF0YSA9IG1ldGEuZGF0LCBzZXggPSAiSW5mYW50IHNleCIsIGZpcnN0UGFydCA9ICJIZWlnaHQgbW9udGggMSIsDQogICAgICAgICAgICAgICBzZWNvbmRQYXJ0ID0gJ1NhbXBsZV9hZ2UoMU1PKScsIGluZGV4ID0gImxmYSIsIG91dHB1dCA9ICJoYXouMW0iKQ0KDQptZXRhLmRhdCA8LSBhZGRXR1NSKGRhdGEgPSBtZXRhLmRhdCwgc2V4ID0gIkluZmFudCBzZXgiLCBmaXJzdFBhcnQgPSAiSGVpZ2h0IG1vbnRoIDYiLA0KICAgICAgICAgICAgICAgc2Vjb25kUGFydCA9ICcxODBkYXlzJywgaW5kZXggPSAibGZhIiwgb3V0cHV0ID0gImhhei42bSIpDQoNCm1ldGEuZGF0JGRlbHRhLmhheiA8LSBtZXRhLmRhdCRoYXouNm0gLSBtZXRhLmRhdCRoYXouMW0NCg0KI1dlaWdodCBmb3IgYWdlDQoNCm1ldGEuZGF0IDwtIGFkZFdHU1IoZGF0YSA9IG1ldGEuZGF0LCBzZXggPSAiSW5mYW50IHNleCIsIGZpcnN0UGFydCA9ICJXZWlnaHQgbW9udGggMSIsDQogICAgICAgICAgICAgICBzZWNvbmRQYXJ0ID0gJ1NhbXBsZV9hZ2UoMU1PKScsIGluZGV4ID0gImxmYSIsIG91dHB1dCA9ICJ3YXouMW0iKQ0KDQptZXRhLmRhdCA8LSBhZGRXR1NSKGRhdGEgPSBtZXRhLmRhdCwgc2V4ID0gIkluZmFudCBzZXgiLCBmaXJzdFBhcnQgPSAiV2VpZ2h0IG1vbnRoIDYiLA0KICAgICAgICAgICAgICAgc2Vjb25kUGFydCA9ICcxODBkYXlzJywgaW5kZXggPSAibGZhIiwgb3V0cHV0ID0gIndhei42bSIpDQoNCm1ldGEuZGF0JGRlbHRhLndheiA8LSBtZXRhLmRhdCR3YXouNm0gLSBtZXRhLmRhdCR3YXouMW0NCmBgYA0KDQoNCiMjIERlZmluZSBrZXkgdmFyaWFibGVzDQoNCmBgYHtyfQ0KI2NvbG5hbWVzKG1ldGEub3V0Y29tZXMpDQoNCmtleS52YXJzIDwtIGMoIlN0cmVzc19ncm91cCIsDQogICAgICAgICAgICJTZXhfY2hpbGQiLA0KICAgICAgICAgICAiUFNTX3N0cmVzc19zY29yZSIsDQogICAgICAgICAgICJMU0NyX3N0cmVzc19zY29yZSIsDQogICAgICAgICAgICJFZHVjYXRpb25fbW90aGVyIiwNCiAgICAgICAgICAgIkJNSV9tb3RoZXIiLA0KICAgICAgICAgICAiVGltZXBvaW50Ig0KICAgICAgICAgICAjICJIYWlyIGNvcnRpc29sIiwNCiAgICAgICAgICAgIyAiSE1fY29ydGlzb2xfQVVDXzEiLA0KICAgICAgICAgICAjIlNhbGl2YV9jb3J0aXNvbF9tb3JuaW5nX3BlYWsiDQogICAgICAgICAgICAgICAgICAgICAgKQ0KDQprZXkudmFycy5pbmYgPC0gYygiSW5mYW50X3RlbXBfTkVHIiwNCiAgICAgICAgICAgIkluZmFudF90ZW1wX1JFRyIsDQogICAgICAgICAgICJJbmZhbnRfdGVtcF9TVVIiLA0KICAgICAgICAgICAiSW5mYW50X3dlaWdodF93MiIsDQogICAgICAgICAgICJJbmZhbnRfd2VpZ2h0XzNtIiwNCiAgICAgICAgICAgIlRpbWVwb2ludCINCikNCg0Ka2V5LnZhcnMuY29ydGlzb2wgPC0gYygiSGFpciBjb3J0aXNvbCIsDQogICAgICAgICAgICJITV9jb3J0aXNvbF9BVUNfMSIsDQogICAgICAgICAgICJITV9jb3J0aXNvbF9BVUNfMiIsDQogICAgICAgICAgICMgIkhNX2NvcnRpc29sX21vcm5pbmdfcGVha18xIiwNCiAgICAgICAgICAgIyAiSE1fY29ydGlzb2xfbW9ybmluZ19wZWFrXzIiLA0KICAgICAgICAgICAiU2FsaXZhX2NvcnRpc29sX21vcm5pbmdfcGVhayIsDQogICAgICAgICAgICJUaW1lcG9pbnQiDQopDQpgYGANCg0KDQpgYGB7cn0NCm1ldGEgPC0gc2FtcGxlX2RhdGEoUFNCKSAlPiUgdW5jbGFzcygpICU+JSBhcy5kYXRhLmZyYW1lKCkNCmBgYA0KDQojIEZpbHRlcmluZw0KDQojIyBSZW1vdmUgbG93LWFidW5kYW5jZSBBU1ZzDQoNClJlbW92ZSB0YXhhIG5vdCBzZWVuIGZvdW5kIGluIGF0IGxlYXN0IDMgc2FtcGxlcyB3aXRoIGEgdG90YWwgY291bnQgb2YgbWluaW11bSAxMDAwIHJlYWRzLiBUaGlzIHByb3RlY3RzIGFnYWluc3QgYW4gT1RVIHdpdGggc21hbGwgbWVhbiAmIHRyaXZpYWxseSBsYXJnZSBDLlYuDQoNCmBgYHtyLCBtZXNzYWdlID0gRiwgZXZhbCA9IFR9DQpwcmV2IDwtIDMvbnJvdyhQU0JAc2FtX2RhdGEpDQpQU0IuZmlsID0gbWV0YWdNaXNjOjpwaHlsb3NlcV9maWx0ZXJfcHJldmFsZW5jZShQU0IsIHByZXYudHJoID0gcHJldiwgYWJ1bmQudHJoID0gNTAwLCBhYnVuZC50eXBlID0gInRvdGFsIiwgdGhyZXNob2xkX2NvbmRpdGlvbiA9ICJBTkQiKQ0KDQpzcGVjIDwtIHNwZWNudW1iZXIoYXMubWF0cml4KG90dV90YWJsZShQU0IuZmlsKSkpICU+JSBzb3J0KGRlY3JlYXNpbmc9RkFMU0UpDQpoZWFkKHNwZWMpDQoNCnN1bShzYW1wbGVfc3VtcyhQU0IuZmlsKSkvc3VtKHNhbXBsZV9zdW1zKFBTQikpDQoNClBTQiA8LSBQU0IuZmlsDQoNCmBgYA0KDQo5Ny41JSBvZiByZWFkcyB3ZXJlIGtlcHQgYWZ0ZXIgZmlsdGVyaW5nLCBidXQgbnVtYmVyIG9mIHRheGEgcmVkdWNlZCBmcm9tIDIwNjMgdG8gMjUwDQogICAgICAgICAgICANCiMjIENTUyBub3JtYWxpemF0aW9uDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IEYsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCg0KUFNCLkNTUyA8LSBtZXRhZ01pc2M6OnBoeWxvc2VxX3RyYW5zZm9ybV9jc3MoUFNCKQ0KYGBgDQoNCiMgU2F2ZSBvYmplY3RzDQoNCmBgYHtyfQ0KbWV0YSA8LSBQU0JAc2FtX2RhdGEgJT4lIGFzLmRhdGEuZnJhbWUoKQ0KDQpzYXZlKGxpc3Q9YygiUFNCIiwiUFNCLkNTUyIsIm1ldGEiLCJrZXkudmFycyIsImtleS52YXJzLmluZiIsImtleS52YXJzLmNvcnRpc29sIiksDQogICAgZmlsZSA9ICJDdXJhdGVkX0FNUy5SRGF0YSINCiAgICApDQpgYGANCg0KDQpSZWFkIGNvdW50IHBlciBzYW1wbGUNCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQ0KYXMudGFibGUoc2FtcGxlX3N1bXMoUFNCKSkNCg0KYGBgDQoNCiMgQmFycGxvdHMNCg0KIyMgQWxsIHNhbXBsZXMNCg0KIyMjIEdlbnVzDQoNClNhbXBsZXMgbG9vayBxdWl0ZSBzaW1pbGFyIGluIGNvbXBvc3Rpb24sIGFwYXJ0IGZyb20gc2FtcGxlIDM3MjgxIGFuZCAzNzI5MS4gMzc3MjgxIGhhZCB2ZXJ5IGxvdyBvYnNlcnZlZCBBU1YgY291bnQsIHNvIGl0IGlzIHJlbW92ZWQuDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCg0KYmFjLnBoeWwuZ2VudXMgPC0gdGF4X2dsb20oUFNCLCAiR2VudXMiLCBOQXJtID0gRkFMU0UpDQoNCnBzMCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhiYWMucGh5bC5nZW51cywgZnVuY3Rpb24oeCkgeCAvIHN1bSh4KSkNCg0KI3BzMTwtIG1lcmdlX3NhbXBsZXMocHMwLCAiVGltZSIpDQoNCiNwczEgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMocHMwLCBmdW5jdGlvbih4KSB4IC8gc3VtKHgpKQ0KDQoNCiNDcmVhdGUgbWVsdGVkIGRhdGFmcmFtZQ0KZGYgPC0gcHNtZWx0KHBzMCkNCg0KI1NlbGVjdCBsYXN0IG5vbi1lbXB0eSB0YXhvbm9taWMgcmFuaw0KZGZbZGY9PSIiXSA8LSBOQQ0KDQpkZiR0YXggPC0gYXBwbHkoZGYsIDEsIGZ1bmN0aW9uKHgpIHRhaWwobmEub21pdCh4KSwgMSkpDQoNCiNBcnJhbmdlIHNhbXBsZXMgYnkgbWVhbiBhYnVuZGFuY2UNCnRvcCA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkodGF4KSAlPiUNCiAgZHBseXI6OnN1bW1hcml6ZShNZWFuID0gbWVhbihBYnVuZGFuY2UpKSAlPiUNCiAgYXJyYW5nZSgtTWVhbikNCiNTaG93IHRvcA0KI3RvcA0KDQp0b3AxMCA8LSB0b3AkdGF4WzE6MTBdDQpkZjAgPC0gZGYgJT4lDQogIG11dGF0ZSh0YXggPSBmY3Rfb3RoZXIodGF4LCBjKGFzLm1hdHJpeCh0b3AxMCkpKSkNCg0KZGYwIDwtIGRmMFtvcmRlcihkZjAkU2FtcGxlLCBkZWNyZWFzaW5nID0gVFJVRSksIF0NCg0KI1NldCBvcmRlciBmb3Igc2FtcGxlcw0KI2RmMCRUcmVhdG1lbnQgPC0gZmFjdG9yKGRmMCRUcmVhdG1lbnQsIGxldmVscyA9IGMoIkNvbnRyb2wiLCAiQW1wIiwgIkZPUCIsICJMTSIsICJMTStBbXAiLCAiTE0rRk9QIikpDQoNCiNTZXQgSG91cnMgYXMgZmFjdG9yDQojJEhvdXJzIDwtIGZhY3RvcihkZjAkSG91cnMsIGxldmVscyA9IGMoIjNoIiwgIjZoIiwgIjI0aCIpKQ0KDQojT3JkZXIgYnkgYWJ1bmRhbmNlIG1vc3QgY29tbW9uIHRheGENCg0KI2RmMCRELklEIDwtIGFzLmZhY3RvcihvcmRlci5kYXQkRC5JRCkNCm9yZGVyIDwtIHN1YnNldChkZjAsIHRheCA9PSB0b3AkdGF4WzFdKSAlPiUgYXJyYW5nZSgtQWJ1bmRhbmNlKQ0KZGYwJElEIDwtIGZhY3RvcihkZjAkSUQsbGV2ZWxzID0gb3JkZXIkSUQgKQ0KDQoNCmRmMCR0YXggPC0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZGYwJHRheCwgZGYwJEFidW5kYW5jZSwgLmZ1biA9IG1lYW4pDQpsYWJlbHMgPSBsZXZlbHMoZGYwJHRheCkNCmxhYmVsc1tsYWJlbHMgIT0gIk90aGVyIl0gPC0gcGFzdGUwKCIqIiwgbGFiZWxzW2xhYmVscyAhPSAiT3RoZXIiXSwgIioiKQ0KYmFyLmZpbGwgPC0gYygiZ3JleSIscmVwKGNvbF9maWwsNSlbMTpsZW5ndGgobGV2ZWxzKGRmMCR0YXgpKS0xXSkgIyBTZXQgZ3JleSBhcyBsYXN0IGNvbG9yID0gT3RoZXINCg0KYmFycGxvdC5hbGwuc2FtcGxlcyA8LSBnZ3Bsb3QoZGYwLCBhZXMoeCA9IElELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEFidW5kYW5jZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBmY3RfcmVvcmRlcih0YXgsIEFidW5kYW5jZSwgLmZ1biA9IG1lYW4pKSkgKyANCiAgZ2VvbV9jb2wod2lkdGggPSAwLjgpICsNCiAgc2NhbGVfZmlsbF9qY28obmFtZSA9ICJUYXhvbm9teSIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWJhci5maWxsLG5hbWU9IkdlbnVzIixsYWJlbHM9bGFiZWxzKSsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzPWVsZW1lbnRfbGluZShzaXplPTEsIGNvbG91ciA9ICJCbGFjayIpLA0KICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF9tYXJrZG93bigpLA0KICApICsNCiAgeWxhYigiUmVsYXRpdmUgYWJ1bmRhbmNlIikNCg0KDQpiYXJwbG90LmFsbC5zYW1wbGVzDQoNCiMgZXh0cmFjdCB0aGUgbGVnZW5kIGZyb20gb25lIG9mIHRoZSBwbG90cw0KbGVnZW5kLmJhcnBsb3QuYWxsIDwtIGdldF9sZWdlbmQoDQogICMgY3JlYXRlIHNvbWUgc3BhY2UgdG8gdGhlIGxlZnQgb2YgdGhlIGxlZ2VuZA0KICBiYXJwbG90LmFsbC5zYW1wbGVzICsgdGhlbWUobGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMTIpKQ0KKQ0KDQpgYGANCg0KIyMjIFBoeWx1bQ0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQoNCmJhYy5waHlsLmZhbWlseSA8LSB0YXhfZ2xvbShQU0IsICJQaHlsdW0iLCBOQXJtID0gRkFMU0UpDQoNCnBzMCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhiYWMucGh5bC5mYW1pbHksIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkpDQoNCg0KI0NyZWF0ZSBtZWx0ZWQgZGF0YWZyYW1lDQpkZiA8LSBwc21lbHQocHMwKQ0KDQojU2VsZWN0IGxhc3Qgbm9uLWVtcHR5IHRheG9ub21pYyByYW5rDQpkZltkZj09IiJdIDwtIE5BDQoNCmRmJHRheCA8LSBhcHBseShkZiwgMSwgZnVuY3Rpb24oeCkgdGFpbChuYS5vbWl0KHgpLCAxKSkNCg0KI0FycmFuZ2Ugc2FtcGxlcyBieSBtZWFuIGFidW5kYW5jZQ0KdG9wIDwtIGRmICU+JQ0KICBncm91cF9ieSh0YXgpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKE1lYW4gPSBtZWFuKEFidW5kYW5jZSkpICU+JQ0KICBhcnJhbmdlKC1NZWFuKQ0KI1Nob3cgdG9wDQojdG9wDQoNCnRvcDEwIDwtIHRvcCR0YXhbMToxMF0NCmRmMCA8LSBkZiAlPiUNCiAgbXV0YXRlKHRheCA9IGZjdF9vdGhlcih0YXgsIGMoYXMubWF0cml4KHRvcDEwKSkpKQ0KDQpkZjAgPC0gZGYwW29yZGVyKGRmMCRTYW1wbGUsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQ0KDQojU2V0IHBoeWx1bSBmb3Igc2FtcGxlcw0KI2RmMCRUcmVhdG1lbnQgPC0gZmFjdG9yKGRmMCRUcmVhdG1lbnQsIGxldmVscyA9IGMoIkNvbnRyb2wiLCAiQW1wIiwgIkZPUCIsICJMTSIsICJMTStBbXAiLCAiTE0rRk9QIikpDQoNCiNTZXQgSG91cnMgYXMgZmFjdG9yDQojJEhvdXJzIDwtIGZhY3RvcihkZjAkSG91cnMsIGxldmVscyA9IGMoIjNoIiwgIjZoIiwgIjI0aCIpKQ0KDQojcGh5bHVtIGJ5IGFidW5kYW5jZSBtb3N0IGNvbW1vbiB0YXhhDQoNCiNkZjAkRC5JRCA8LSBhcy5mYWN0b3IocGh5bHVtLmRhdCRELklEKQ0KcGh5bHVtIDwtIHN1YnNldChkZjAsIHRheCA9PSB0b3AkdGF4WzFdKSAlPiUgYXJyYW5nZSgtQWJ1bmRhbmNlKQ0KZGYwJElEIDwtIGZhY3RvcihkZjAkSUQsbGV2ZWxzID0gcGh5bHVtJElEICkNCg0KYmFycGxvdC5hbGwucGh5bHVtIDwtIGdncGxvdChkZjAsIGFlcyh4ID0gSUQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQWJ1bmRhbmNlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGZjdF9yZW9yZGVyKHRheCwgQWJ1bmRhbmNlLCAuZnVuID0gbWVhbikpKSArIA0KICBnZW9tX2NvbCh3aWR0aCA9IDAuOCkgKw0KICBzY2FsZV9maWxsX2pjbyhuYW1lID0gIlRheG9ub215IikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cmVwKGNvbF9maWwsNSksbmFtZT0iUGh5bHVtIikrDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcz1lbGVtZW50X2xpbmUoc2l6ZT0xLCBjb2xvdXIgPSAiQmxhY2siKSwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAid2hpdGUiLCBmaWxsID0gIndoaXRlIiksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICAjbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiKQ0KICAgICAgICAjbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkgKw0KICB5bGFiKCJSZWxhdGl2ZSBhYnVuZGFuY2UiKQ0KDQoNCmJhcnBsb3QuYWxsLnBoeWx1bQ0KYGBgDQoNCiMjIEJ5IHN0cmVzcyBncm91cA0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEYsd2FybmluZz1GfQ0KI2JhYy5waHlsIDwtIHRheF9nbG9tKFBTQiwgIkdlbnVzIiwgTkFybSA9IEZBTFNFKQ0KDQpwczAgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoYmFjLnBoeWwuZ2VudXMsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkpDQoNCnBzMTwtIHBoeWxvc2VxOjptZXJnZV9zYW1wbGVzKHBzMCwgIlN0cmVzc19ncm91cCIpDQoNCnBzMSA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhwczEsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkpDQoNCg0KI0NyZWF0ZSBtZWx0ZWQgZGF0YWZyYW1lDQpkZiA8LSBwc21lbHQocHMxKQ0KDQojU2VsZWN0IGxhc3Qgbm9uLWVtcHR5IHRheG9ub21pYyByYW5rDQpkZltkZj09IiJdIDwtIE5BDQoNCmRmJHRheCA8LSBhcHBseShkZiwgMSwgZnVuY3Rpb24oeCkgdGFpbChuYS5vbWl0KHgpLCAxKSkNCg0KI0FycmFuZ2Ugc2FtcGxlcyBieSBtZWFuIGFidW5kYW5jZQ0KdG9wIDwtIGRmICU+JQ0KICBncm91cF9ieSh0YXgpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKE1lYW4gPSBtZWFuKEFidW5kYW5jZSkpICU+JQ0KICBhcnJhbmdlKC1NZWFuKQ0KI1Nob3cgdG9wDQojdG9wDQoNCnRvcDEwIDwtIHRvcCR0YXhbMToxMF0NCmRmMCA8LSBkZiAlPiUNCiAgbXV0YXRlKHRheCA9IGZjdF9vdGhlcih0YXgsIGMoYXMubWF0cml4KHRvcDEwKSkpKQ0KDQpkZjAgPC0gZGYwW29yZGVyKGRmMCRTYW1wbGUsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQ0KDQojU2V0IG9yZGVyIGZvciBzYW1wbGVzDQojZGYwJFRyZWF0bWVudCA8LSBmYWN0b3IoZGYwJFRyZWF0bWVudCwgbGV2ZWxzID0gYygiQ29udHJvbCIsICJBbXAiLCAiRk9QIiwgIkxNIiwgIkxNK0FtcCIsICJMTStGT1AiKSkNCg0KI1NldCBIb3VycyBhcyBmYWN0b3INCiMkSG91cnMgPC0gZmFjdG9yKGRmMCRIb3VycywgbGV2ZWxzID0gYygiM2giLCAiNmgiLCAiMjRoIikpDQoNCiNPcmRlciBieSBhYnVuZGFuY2UgbW9zdCBjb21tb24gdGF4YQ0KDQojZGYwJEQuSUQgPC0gYXMuZmFjdG9yKG9yZGVyLmRhdCRELklEKQ0KDQpkZjAkdGF4IDwtIGZvcmNhdHM6OmZjdF9yZW9yZGVyKGRmMCR0YXgsIGRmMCRBYnVuZGFuY2UsIC5mdW4gPSBtZWFuKQ0KbGFiZWxzID0gbGV2ZWxzKGRmMCR0YXgpDQpsYWJlbHNbbGFiZWxzICE9ICJPdGhlciJdIDwtIHBhc3RlMCgiKiIsIGxhYmVsc1tsYWJlbHMgIT0gIk90aGVyIl0sICIqIikNCmJhci5maWxsIDwtIGMoImdyZXkiLHJlcChjb2xfZmlsLDUpWzE6bGVuZ3RoKGxldmVscyhkZjAkdGF4KSktMV0pICMgU2V0IGdyZXkgYXMgbGFzdCBjb2xvciA9IE90aGVyDQoNCmJhcnBsb3QuZ3JvdXAgPC0gZ2dwbG90KGRmMCwgYWVzKFNhbXBsZSwgQWJ1bmRhbmNlLCBmaWxsID0gZmN0X3Jlb3JkZXIodGF4LCBBYnVuZGFuY2UsIC5mdW4gPSBtZWFuKSkpICsgDQogIGdlb21fY29sKHdpZHRoID0gMC44KSArDQogIHNjYWxlX2ZpbGxfamNvKG5hbWUgPSAiVGF4b25vbXkiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1iYXIuZmlsbCxuYW1lPSJHZW51cyIpKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpDQogICAgICAgICNsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKSArDQogIHlsYWIoIlJlbGF0aXZlIGFidW5kYW5jZSIpDQoNCg0KYmFycGxvdC5ncm91cA0KDQpgYGANCg0KIyMgQnkgdGltZSBwb2ludA0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEYsd2FybmluZz1GfQ0KIyBiYWMucGh5bCA8LSB0YXhfZ2xvbShQU0IsICJHZW51cyIsIE5Bcm0gPSBGQUxTRSkNCg0KcHMwIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKGJhYy5waHlsLmdlbnVzLCBmdW5jdGlvbih4KSB4IC8gc3VtKHgpKQ0KDQpwczE8LSBtZXJnZV9zYW1wbGVzKHBzMCwgIkRheSIpDQoNCnBzMSA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhwczEsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkpDQoNCg0KI0NyZWF0ZSBtZWx0ZWQgZGF0YWZyYW1lDQpkZiA8LSBwc21lbHQocHMxKQ0KDQojU2VsZWN0IGxhc3Qgbm9uLWVtcHR5IHRheG9ub21pYyByYW5rDQpkZltkZj09IiJdIDwtIE5BDQoNCmRmJHRheCA8LSBhcHBseShkZiwgMSwgZnVuY3Rpb24oeCkgdGFpbChuYS5vbWl0KHgpLCAxKSkNCg0KI0FycmFuZ2Ugc2FtcGxlcyBieSBtZWFuIGFidW5kYW5jZQ0KdG9wIDwtIGRmICU+JQ0KICBncm91cF9ieSh0YXgpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKE1lYW4gPSBtZWFuKEFidW5kYW5jZSkpICU+JQ0KICBhcnJhbmdlKC1NZWFuKQ0KI1Nob3cgdG9wDQojdG9wDQoNCnRvcDEwIDwtIHRvcCR0YXhbMToxMF0NCmRmMCA8LSBkZiAlPiUNCiAgbXV0YXRlKHRheCA9IGZjdF9vdGhlcih0YXgsIGMoYXMubWF0cml4KHRvcDEwKSkpKQ0KDQpkZjAgPC0gZGYwW29yZGVyKGRmMCRTYW1wbGUsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQ0KDQojU2V0IG9yZGVyIGZvciBzYW1wbGVzDQojZGYwJFRyZWF0bWVudCA8LSBmYWN0b3IoZGYwJFRyZWF0bWVudCwgbGV2ZWxzID0gYygiQ29udHJvbCIsICJBbXAiLCAiRk9QIiwgIkxNIiwgIkxNK0FtcCIsICJMTStGT1AiKSkNCg0KI1NldCBIb3VycyBhcyBmYWN0b3INCiMkSG91cnMgPC0gZmFjdG9yKGRmMCRIb3VycywgbGV2ZWxzID0gYygiM2giLCAiNmgiLCAiMjRoIikpDQoNCiNPcmRlciBieSBhYnVuZGFuY2UgbW9zdCBjb21tb24gdGF4YQ0KDQojZGYwJEQuSUQgPC0gYXMuZmFjdG9yKG9yZGVyLmRhdCRELklEKQ0KDQpiYXIuZmlsbCA8LSBjKCJncmV5IixyZXAoY29sX2ZpbCw1KVsxOmxlbmd0aChsZXZlbHMoZGYwJHRheCkpLTFdKSAjIFNldCBncmV5IGFzIGxhc3QgY29sb3IgPSBPdGhlcg0KDQpiYXJwbG90LmRheXMgPC0gZ2dwbG90KGRmMCwgYWVzKFNhbXBsZSwgQWJ1bmRhbmNlLCBmaWxsID0gZmN0X3Jlb3JkZXIodGF4LCBBYnVuZGFuY2UsIC5mdW4gPSBtZWFuKSkpICsgDQogIGdlb21fY29sKHdpZHRoID0gMC44KSArDQogIHNjYWxlX2ZpbGxfamNvKG5hbWUgPSAiVGF4b25vbXkiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1iYXIuZmlsbCxuYW1lPSJHZW51cyIpKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpDQogICAgICAgICNsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKSArDQogIHlsYWIoIlJlbGF0aXZlIGFidW5kYW5jZSIpDQoNCg0KYmFycGxvdC5kYXlzDQpgYGANCg0KIyMgQnkgU3Rlc3MgYW5kIHRpbWUgcG9pbnQNCg0KIyMjIEdlbnVzDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRix3YXJuaW5nPUZ9DQpiYWMucGh5bC5nZW51c0BzYW1fZGF0YSRTdHJlc3NfdGltZSA8LSBwYXN0ZTAoUFNCQHNhbV9kYXRhJFN0cmVzc19ncm91cCwiICIsUFNCQHNhbV9kYXRhJERheSkNCg0KI2JhYy5waHlsIDwtIHRheF9nbG9tKFBTQiwgIkdlbnVzIiwgTkFybSA9IEZBTFNFKQ0KDQpwczAgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoYmFjLnBoeWwuZ2VudXMsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkpDQoNCnBzMTwtIG1lcmdlX3NhbXBsZXMocHMwLCAiU3RyZXNzX3RpbWUiKQ0KDQpwczEgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMocHMxLCBmdW5jdGlvbih4KSB4IC8gc3VtKHgpKQ0KDQoNCiNDcmVhdGUgbWVsdGVkIGRhdGFmcmFtZQ0KZGYgPC0gcHNtZWx0KHBzMSkNCg0KI1NlbGVjdCBsYXN0IG5vbi1lbXB0eSB0YXhvbm9taWMgcmFuaw0KZGZbZGY9PSIiXSA8LSBOQQ0KDQpkZiR0YXggPC0gYXBwbHkoZGYsIDEsIGZ1bmN0aW9uKHgpIHRhaWwobmEub21pdCh4KSwgMSkpDQoNCiNBcnJhbmdlIHNhbXBsZXMgYnkgbWVhbiBhYnVuZGFuY2UNCnRvcCA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkodGF4KSAlPiUNCiAgZHBseXI6OnN1bW1hcml6ZShNZWFuID0gbWVhbihBYnVuZGFuY2UpKSAlPiUNCiAgYXJyYW5nZSgtTWVhbikNCiNTaG93IHRvcA0KI3RvcA0KDQp0b3AxMCA8LSB0b3AkdGF4WzE6MTBdDQpkZjAgPC0gZGYgJT4lDQogIG11dGF0ZSh0YXggPSBmY3Rfb3RoZXIodGF4LCBjKGFzLm1hdHJpeCh0b3AxMCkpKSkNCg0KZGYwIDwtIGRmMFtvcmRlcihkZjAkU2FtcGxlLCBkZWNyZWFzaW5nID0gVFJVRSksIF0NCg0KI1NldCBvcmRlciBmb3Igc2FtcGxlcw0KI2RmMCRUcmVhdG1lbnQgPC0gZmFjdG9yKGRmMCRUcmVhdG1lbnQsIGxldmVscyA9IGMoIkNvbnRyb2wiLCAiQW1wIiwgIkZPUCIsICJMTSIsICJMTStBbXAiLCAiTE0rRk9QIikpDQoNCiNTZXQgSG91cnMgYXMgZmFjdG9yDQojJEhvdXJzIDwtIGZhY3RvcihkZjAkSG91cnMsIGxldmVscyA9IGMoIjNoIiwgIjZoIiwgIjI0aCIpKQ0KDQojT3JkZXIgYnkgYWJ1bmRhbmNlIG1vc3QgY29tbW9uIHRheGENCg0KI2RmMCRELklEIDwtIGFzLmZhY3RvcihvcmRlci5kYXQkRC5JRCkNCg0KZGYwJHRheCA8LSBmb3JjYXRzOjpmY3RfcmVvcmRlcihkZjAkdGF4LCBkZjAkQWJ1bmRhbmNlLCAuZnVuID0gbWVhbikNCmxhYmVscyA9IGxldmVscyhkZjAkdGF4KQ0KbGFiZWxzW2xhYmVscyAhPSAiT3RoZXIiXSA8LSBwYXN0ZTAoIioiLCBsYWJlbHNbbGFiZWxzICE9ICJPdGhlciJdLCAiKiIpDQpiYXIuZmlsbCA8LSBjKCJncmV5IixyZXAoY29sX2ZpbCw1KVsxOmxlbmd0aChsZXZlbHMoZGYwJHRheCkpLTFdKSAjIFNldCBncmV5IGFzIGxhc3QgY29sb3IgPSBPdGhlcg0KDQpiYXJwbG90LnN0cmVzcy50aW1lLmdlbnVzIDwtIGdncGxvdChkZjAsIGFlcyhTYW1wbGUsIEFidW5kYW5jZSwgZmlsbCA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKHRheCwgQWJ1bmRhbmNlLCAuZnVuID0gbWVhbikpKSArIA0KICBnZW9tX2NvbCh3aWR0aCA9IDAuOCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YmFyLmZpbGwsbmFtZT0iR2VudXMiLGxhYmVscyA9IGxhYmVscykrDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGF4aXMubGluZT1lbGVtZW50X2xpbmUoc2l6ZT0wLjUpLA0KICAgICAgICAjcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpDQogICAgICAgICNsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKSArDQogIHlsYWIoIlJlbGF0aXZlIGFidW5kYW5jZSIpDQoNCg0KYmFycGxvdC5zdHJlc3MudGltZS5nZW51cw0KDQpgYGANCiMjIyBQaHlsdW0NCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGLHdhcm5pbmc9Rn0NCmJhYy5waHlsLnBoeWx1bSA8LSB0YXhfZ2xvbShQU0IsICJQaHlsdW0iLCBOQXJtID0gRkFMU0UpDQoNCmJhYy5waHlsLnBoeWx1bUBzYW1fZGF0YSRTdHJlc3NfdGltZSA8LSBwYXN0ZTAoYmFjLnBoeWwucGh5bHVtQHNhbV9kYXRhJFN0cmVzc19ncm91cCwiICIsUFNCQHNhbV9kYXRhJERheSkNCg0KcHMwIDwtIHRyYW5zZm9ybV9zYW1wbGVfY291bnRzKGJhYy5waHlsLnBoeWx1bSwgZnVuY3Rpb24oeCkgeCAvIHN1bSh4KSkNCg0KcHMxPC0gbWVyZ2Vfc2FtcGxlcyhwczAsICJTdHJlc3NfdGltZSIpDQoNCnBzMSA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhwczEsIGZ1bmN0aW9uKHgpIHggLyBzdW0oeCkpDQoNCg0KI0NyZWF0ZSBtZWx0ZWQgZGF0YWZyYW1lDQpkZiA8LSBwc21lbHQocHMxKQ0KDQojU2VsZWN0IGxhc3Qgbm9uLWVtcHR5IHRheG9ub21pYyByYW5rDQpkZltkZj09IiJdIDwtIE5BDQoNCmRmJHRheCA8LSBhcHBseShkZiwgMSwgZnVuY3Rpb24oeCkgdGFpbChuYS5vbWl0KHgpLCAxKSkNCg0KI0FycmFuZ2Ugc2FtcGxlcyBieSBtZWFuIGFidW5kYW5jZQ0KdG9wIDwtIGRmICU+JQ0KICBncm91cF9ieSh0YXgpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKE1lYW4gPSBtZWFuKEFidW5kYW5jZSkpICU+JQ0KICBhcnJhbmdlKC1NZWFuKQ0KI1Nob3cgdG9wDQojdG9wDQoNCnRvcDEwIDwtIHRvcCR0YXhbMToxMF0NCmRmMCA8LSBkZiAlPiUNCiAgbXV0YXRlKHRheCA9IGZjdF9vdGhlcih0YXgsIGMoYXMubWF0cml4KHRvcDEwKSkpKQ0KDQpkZjAgPC0gZGYwW29yZGVyKGRmMCRTYW1wbGUsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQ0KDQojU2V0IG9yZGVyIGZvciBzYW1wbGVzDQojZGYwJFRyZWF0bWVudCA8LSBmYWN0b3IoZGYwJFRyZWF0bWVudCwgbGV2ZWxzID0gYygiQ29udHJvbCIsICJBbXAiLCAiRk9QIiwgIkxNIiwgIkxNK0FtcCIsICJMTStGT1AiKSkNCg0KI1NldCBIb3VycyBhcyBmYWN0b3INCiMkSG91cnMgPC0gZmFjdG9yKGRmMCRIb3VycywgbGV2ZWxzID0gYygiM2giLCAiNmgiLCAiMjRoIikpDQoNCiNPcmRlciBieSBhYnVuZGFuY2UgbW9zdCBjb21tb24gdGF4YQ0KDQojZGYwJEQuSUQgPC0gYXMuZmFjdG9yKG9yZGVyLmRhdCRELklEKQ0KDQpiYXJwbG90LnN0cmVzcy50aW1lLmdlbnVzIDwtIGdncGxvdChkZjAsIGFlcyhTYW1wbGUsIEFidW5kYW5jZSwgZmlsbCA9IGZjdF9yZW9yZGVyKHRheCwgQWJ1bmRhbmNlLCAuZnVuID0gbWVhbikpKSArIA0KICBnZW9tX2NvbCh3aWR0aCA9IDAuOCkgKw0KICBzY2FsZV9maWxsX2pjbyhuYW1lID0gIlRheG9ub215IikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cmVwKGNvbF9maWwsNSksbmFtZT0iUGh5bHVtIikrDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGF4aXMubGluZT1lbGVtZW50X2xpbmUoc2l6ZT0wLjUpLA0KICAgICAgICAjcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICAjbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkgKw0KICB5bGFiKCJSZWxhdGl2ZSBhYnVuZGFuY2UiKQ0KDQoNCmJhcnBsb3Quc3RyZXNzLnRpbWUuZ2VudXMNCg0KYGBgDQoNCiMgUmVsYXRpdmUgYWJ1bmRhbmNlIHZpb2xpbiBwbG90DQoNCiMjIFN0cmVzcyBncm91cA0KDQpgYGB7ciwgbWVzc2FnZSA9IEZ9DQojcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImpzdG9raG9sbS9yYWJ1cGxvdCIpDQpsaWJyYXJ5KHJhYnVwbG90KQ0KDQpyYWJ1Lmdyb3VwIDwtIHJhYnVwbG90KA0KICBQU0IsDQogIHZpb2xpbiA9IFRSVUUsIHByZWRpY3RvciA9ICJTdHJlc3NfZ3JvdXAiLCBwX2FkanVzdCA9IFRSVUUsIHBfc3RhcnMgPSBUUlVFICxjb2xvcnMgPSBjb2xfZmlsWzE6Ml0sdGV4dF9hbmdsZV94ID0gNDUpDQoNCnJhYnUuZ3JvdXAgPC0gcmFidS5ncm91cCArIA0KICAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKCJTdHJlc3MgZ3JvdXAiKSkgDQoNCnJhYnUuZ3JvdXANCmBgYA0KDQoNCiMjIyBBZGp1c3RlZCBmb3IgdGltZXBvaW50DQoNCmBgYHtyLCBtZXNzYWdlID0gRn0NCnJhYnUuZ3JvdXAuYWRqX3RpbWUgPC0gcmFidXBsb3QoDQogIFBTQiwNCiAgdmlvbGluID0gVFJVRSwgcHJlZGljdG9yID0gIlN0cmVzc19ncm91cCIsDQogIFRpbWUgID0gIlRpbWVjb2RlIiwNCiAgcF9hZGp1c3QgPSBUUlVFLCBwX3N0YXJzID0gVFJVRSAsY29sb3JzID0gY29sX2ZpbFsxOjJdLCBzdGF0cyA9ICJub24tcGFyYW1ldHJpYyIpDQoNCnJhYnUuZ3JvdXAuYWRqX3RpbWUNCmBgYA0KDQojIyMgU3ViamVjdCBpZA0KDQpgYGB7ciwgbWVzc2FnZSA9IEZ9DQpyYWJ1Lmdyb3VwLmFkal90aW1lIDwtIHJhYnVwbG90KA0KICBQU0IsDQogIHZpb2xpbiA9IFRSVUUsIHByZWRpY3RvciA9ICJTdHJlc3NfZ3JvdXAiLCBpZD0iU3ViamVjdF9JRCIscF9hZGp1c3QgPSBUUlVFLCBwX3N0YXJzID0gVFJVRSAsY29sb3JzID0gY29sX2ZpbFsxOjJdKQ0KDQpyYWJ1Lmdyb3VwLmFkal90aW1lDQpgYGANCg0KIyMjIFNwZWNpZXMNCg0KYGBge3IsIG1lc3NhZ2UgPSBGfQ0KI3JlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJqc3Rva2hvbG0vcmFidXBsb3QiKQ0KbGlicmFyeShyYWJ1cGxvdCkNCg0KcmFidS5ncm91cC5zcGVjaWVzIDwtIHJhYnVwbG90KA0KICBQU0IsDQogIHZpb2xpbiA9IFRSVUUsIHByZWRpY3RvciA9ICJTdHJlc3NfZ3JvdXAiLCBwX2FkanVzdCA9IFRSVUUsIHBfc3RhcnMgPSBUUlVFICxjb2xvcnMgPSBjb2xfZmlsWzE6Ml0sdHlwZT0iU3BlY2llcyIpDQoNCnJhYnUuZ3JvdXAuc3BlY2llcw0KYGBgDQoNCiMjIFRpbWUNCg0KYGBge3IsIG1lc3NhZ2UgPSBGfQ0KcmFidS50aW1lIDwtIHJhYnVwbG90KA0KICBQU0IsDQogIHZpb2xpbiA9IFRSVUUsIHByZWRpY3RvciA9ICJEYXkiLCBwX2FkanVzdCA9IFRSVUUsIHBfc3RhcnMgPSBUUlVFICxjb2xvcnMgPSBjb2xfZmlsWzE6Ml0pDQoNCnJhYnUudGltZQ0KYGBgDQoNCiMjIFN0dWR5IGdyb3VwIG92ZXIgdGltZQ0KDQpgYGB7ciwgbWVzc2FnZSA9IEZ9DQpyYWJ1Lmdyb3VwLnRpbWUgPC0gcmFidXBsb3QoDQogIFBTQiwNCiAgdmlvbGluID0gVFJVRSwgcHJlZGljdG9yID0gIlN0cmVzc19ncm91cCIsIGZhY2V0X3dyYXAgPSAiRGF5IiwgcF9hZGp1c3QgPSBUUlVFLCBwX3N0YXJzID0gVFJVRSAsY29sb3JzID0gY29sX2ZpbFsxOjJdKSArIA0KICAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKCJTdHJlc3MgZ3JvdXAiKSkgKw0KICAgICAgICAgICAgZ2d0aXRsZSgiIikNCg0KcmFidS5ncm91cC50aW1lDQpgYGANCg0KIyBBbHBoYSBkaXZlcnNpdHkNCg0KIyMgU3RyZXNzIGdyb3VwDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRiwgd2FybmluZz1GQUxTRX0NCg0KI05vcm1hbGl6ZSB0byBtZWFuIHJlYWQgY291bnQNCnN0YW5kZiA9IGZ1bmN0aW9uKHgsIHQ9dG90YWwpIHJvdW5kKHQgKiAoeCAvIHN1bSh4KSkpDQp0b3RhbCA9IG1lZGlhbihzYW1wbGVfc3VtcyhQU0IpKQ0KUFNCLlIgPSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhQU0IsIHN0YW5kZikNCg0KI1NldCBkZXNpcmVkIGFscGhhIGRpdmVyc2l0eSBtZXRyaWNzDQoNCmFscGhhX21ldCA8LSBjKCJPYnNlcnZlZCIsICJTaGFubm9uIiwgIkludlNpbXBzb24iKQ0KDQojIyMjIyMjIyMjI0JveHBsb3RzDQoNCiMjVGltZQ0KDQp2YXIgPC0gYygiU3RyZXNzX2dyb3VwIikNCg0KYW5ub3RhdGlvbnMgPC0gZGF0YS5mcmFtZSgNCiAgdmFyaWFibGUgPSBhbHBoYV9tZXQsDQogIExhYmVsID0gYygiTlMiKSwNCiAgeSA9IGMoMTEwLCAzLjIsIDEzKSAgIyBQb3NpdGlvbnMgc2hvdWxkIGJlIGFkanVzdGVkIGJhc2VkIG9uIHlvdXIgZGF0YSdzIHktYXhpcyBzY2FsZXMNCikNCg0KDQphbHBoYS5ncm91cCA8LSBwbG90X3JpY2huZXNzKFBTQi5SLCBtZWFzdXJlcz1hbHBoYV9tZXQgLCB4PXZhciwgY29sb3I9dmFyKSArIA0KICBnZW9tX2JveHBsb3QoYWxwaGE9MC4xLCBsd2QgPSAxKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xfZmlsLCJTdHJlc3MgZ3JvdXAiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gIndoaXRlIiwgZmlsbCA9ICJ3aGl0ZSIpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCkNCiAgKSArDQogIGxhYnMoeD0iIiwNCiAgICAgICB5PSJBbHBoYSBkaXZlcnNpdHkiKSArDQogIGdlb21fdGV4dChkYXRhID0gYW5ub3RhdGlvbnMsIGFlcyh4ID0gMS41LCB5ID0geSwgbGFiZWwgPSBMYWJlbCksIGluaGVyaXQuYWVzID0gRkFMU0UpDQoNCmFscGhhLmdyb3VwDQpgYGANCg0KQW5vdmENCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIHdhcm5pbmcgPSBGfQ0KIyNSaWNobmVzcyAtIGFsbCB0aW1lIHBvaW50cw0KDQpyaWNobmVzcyA9IGVzdGltYXRlX3JpY2huZXNzKFBTQi5SLCBtZWFzdXJlcyA9IGFscGhhX21ldCkNCg0KI1RpbWUNCg0KcmljaCA8LSBjYmluZChyaWNobmVzcywgdmFyaWFibGUgPSBzYW1wbGVfZGF0YShQU0IuUikkU3RyZXNzX2dyb3VwKQ0KDQpUdWtleUhTRChhb3YoU2hhbm5vbiB+IHZhcmlhYmxlLCByaWNoKSkNCmBgYA0KDQojIyBUaW1lDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCB3YXJuaW5nPUZ9DQojIyMjIyMjIyMjI0JveHBsb3RzDQoNCiMjVGltZQ0KDQp2YXJpYWJsZSA8LSBjKCJEYXkiKQ0KDQphbm5vdGF0aW9ucyA8LSBkYXRhLmZyYW1lKA0KICB2YXJpYWJsZSA9IGFscGhhX21ldCwNCiAgTGFiZWwgPSBjKCJOUyIpLA0KICB5ID0gYygxMTAsIDMuMiwgMTMpICAjIFBvc2l0aW9ucyBzaG91bGQgYmUgYWRqdXN0ZWQgYmFzZWQgb24geW91ciBkYXRhJ3MgeS1heGlzIHNjYWxlcw0KKQ0KDQphbHBoYS5kYXlzIDwtIHBsb3RfcmljaG5lc3MoUFNCLlIsIG1lYXN1cmVzPWFscGhhX21ldCAsIHg9dmFyaWFibGUsIGNvbG9yPXZhcmlhYmxlKSArIA0KICBnZW9tX2JveHBsb3QoYWxwaGE9MC4xLCBsd2QgPSAxKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xfZmlsLCIiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLA0KICAgICAgICBheGlzLmxpbmU9ZWxlbWVudF9saW5lKHNpemU9MSksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZSA9IDgsIGNvbG91ciA9ICJCbGFjayIpLA0KICAgICAgICBheGlzLnRpY2tzPWVsZW1lbnRfbGluZShzaXplPTEsIGNvbG91ciA9ICJCbGFjayIpLA0KICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCwgYW5nbGUgPSAwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkgKw0KICBsYWJzKHg9IlRpbWVwb2ludCIsDQogICAgICAgeT0iQWxwaGEgZGl2ZXJzaXR5IikgKw0KICBnZW9tX3RleHQoZGF0YSA9IGFubm90YXRpb25zLCBhZXMoeCA9IDEuNSwgeSA9IHksIGxhYmVsID0gTGFiZWwpLCBpbmhlcml0LmFlcyA9IEZBTFNFKQ0KDQphbHBoYS5kYXlzDQpgYGANCkFub3ZhDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCB3YXJuaW5nPUZ9DQojVHJ1bmsNCg0KcmljaCA8LSBjYmluZChyaWNobmVzcywgdmFyaWFibGUgPSBzYW1wbGVfZGF0YShQU0IuUikkVGltZXBvaW50KQ0KDQpUdWtleUhTRChhb3YoU2hhbm5vbiB+IHZhcmlhYmxlLCByaWNoKSkNCmBgYA0KDQojIEJldGEgZGl2ZXJzaXR5DQoNCiMjIEdyb3VwDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtYXNzYWdlID0gRn0NCiNEbyBQQ29BIG9yZGluYXRpb24gYmFzZWQgb24gQnJheS1jdXJ0aXMgZGlzdGFuY2UNCkdQLm9yZCA8LSBvcmRpbmF0ZShQU0IuQ1NTLCAiUENvQSIsICJicmF5IikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjUnVuICsgQmF0Y2gNCg0KI1BTQi5DU1NAc2FtX2RhdGEkUnVuIDwtIGFzLmZhY3RvcihQU0IuQ1NTQHNhbV9kYXRhJFJ1bikNCg0KYmV0YS5zdHJlc3MgPSBwbG90X29yZGluYXRpb24oUFNCLkNTUywgR1Aub3JkLCBjb2xvcj0iU3RyZXNzX2dyb3VwIikgKyANCiAgc3RhdF9lbGxpcHNlKGdlb20gPSAicG9seWdvbiIsIGxldmVsID0gMC45NSwgZmlsbCA9IE5BLCBzaXplID0gMSkgKw0KICAjc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xfZmlsKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xfZmlsLCJTdHJlc3MgZ3JvdXAiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIixoanVzdCA9IDAuNSksDQogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKQ0KICApICsgDQogICNnZW9tX3BvaW50KGFlcyhzaGFwZSA9IEMuc2VjdGlvbi4uWWVzLk5vLiksIHNpemUgPSAzKSArDQogIHNjYWxlX3hfcmV2ZXJzZSgpICsjIFJldmVydCB4LWF4aXMgdG8gbWF0Y2ggcGxvdHMNCiAgI2dlb21fZGwoYWVzKGxhYmVsID0gRC5JRCksIG1ldGhvZCA9IGxpc3QoZGwudHJhbnMoeCA9IHggKyAwLjApLCAibGFzdC5wb2ludHMiLCBjZXggPSAwLjgpKQ0KICBnZ3Bsb3QyOjphbm5vdGF0ZSgidGV4dCIsIHggPSAtMC4zMywgeSA9IDAuMzgsIGxhYmVsID0gIlAgPSAwLjAwNSIpICNBZGQgcC12YWx1ZSBmcm9tIGFkb25pcw0KDQpiZXRhLnN0cmVzcw0KYGBgDQpQZXJtYW5vdmEgc3RhdGlzdGljcw0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQpQU0IuQ1NTLm5vLm5hIDwtIHN1YnNldF9zYW1wbGVzKFBTQi5DU1MsICFpcy5uYShTdHJlc3NfZ3JvdXApKQ0KDQpEX0JDIDwtIHBoeWxvc2VxOjpkaXN0YW5jZShQU0IuQ1NTLm5vLm5hLCAiYnJheSIpDQoNCmFkb25pcyA8LSBhZG9uaXMyKERfQkMgfiBTdHJlc3NfZ3JvdXAsIGRhdGEgPSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKFBTQi5DU1Mubm8ubmEpKSkNCmFkb25pcw0KYGBgDQoNCiMjIFRpbWVwb2ludA0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWFzc2FnZSA9IEZ9DQojRG8gUENvQSBvcmRpbmF0aW9uIGJhc2VkIG9uIEJyYXktY3VydGlzIGRpc3RhbmNlDQpHUC5vcmQgPC0gb3JkaW5hdGUoUFNCLkNTUywgIlBDb0EiLCAiYnJheSIpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjI1J1biArIEJhdGNoDQoNCiNQU0IuQ1NTQHNhbV9kYXRhJFJ1biA8LSBhcy5mYWN0b3IoUFNCLkNTU0BzYW1fZGF0YSRSdW4pDQoNCmJldGEuZGF5cyA9IHBsb3Rfb3JkaW5hdGlvbihQU0IuQ1NTLCBHUC5vcmQsIGNvbG9yPSJEYXkiKSArIA0KICBzdGF0X2VsbGlwc2UoZ2VvbSA9ICJwb2x5Z29uIiwgbGV2ZWwgPSAwLjk1LCBmaWxsID0gTkEsIHNpemUgPSAxKSArDQogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbF9maWwpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbF9maWxbMzo0XSkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIsaGp1c3QgPSAwLjUpLA0KICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkNCiAgKSArIA0KICAjZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBDLnNlY3Rpb24uLlllcy5Oby4pLCBzaXplID0gMykgKw0KICBzY2FsZV94X3JldmVyc2UoKSArIyBSZXZlcnQgeC1heGlzIHRvIG1hdGNoIHBsb3RzDQogICNnZ3RpdGxlKCJUaW1lcG9pbnQiKSArDQogIGdncGxvdDI6OmFubm90YXRlKCJ0ZXh0IiwgeCA9IC0wLjMsIHkgPSAwLjMsIGxhYmVsID0gIlAgPSBOUyIpICNBZGQgcC12YWx1ZSBmcm9tIGFkb25pcw0KDQpiZXRhLmRheXMNCmBgYA0KDQpQZXJtYW5vdmEgc3RhdGlzdGljcw0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQpQU0IuQ1NTLm5vLm5hIDwtIHN1YnNldF9zYW1wbGVzKFBTQi5DU1MsICFpcy5uYShTdHJlc3NfZ3JvdXApKQ0KDQpEX0JDIDwtIHBoeWxvc2VxOjpkaXN0YW5jZShQU0IuQ1NTLm5vLm5hLCAiYnJheSIpDQoNCmFkb25pcyA8LSBhZG9uaXMyKERfQkMgfiBUaW1lcG9pbnQsIGRhdGEgPSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKFBTQi5DU1Mubm8ubmEpKSkNCmFkb25pcw0KYGBgDQoNCiMjIFN0cmVzcyBzcGxpdCBieSB0aW1lDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCmJldGEuc3RyZXNzLmRheSA8LSBwbG90X29yZGluYXRpb24oUFNCLkNTUywgR1Aub3JkLCBjb2xvcj0iU3RyZXNzX2dyb3VwIikgKyANCiAgc3RhdF9lbGxpcHNlKGdlb20gPSAicG9seWdvbiIsIGxldmVsID0gMC45NSwgZmlsbCA9IE5BLCBzaXplID0gMSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sX2ZpbCkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCxmYWNlID0gImJvbGQiKQ0KICApICsgDQogICNnZW9tX3BvaW50KGFlcyhzaGFwZSA9IEMuc2VjdGlvbi4uWWVzLk5vLiksIHNpemUgPSAzKSArDQogIHNjYWxlX3hfcmV2ZXJzZSgpICsjIFJldmVydCB4LWF4aXMgdG8gbWF0Y2ggcGxvdHMNCiAgZmFjZXRfd3JhcCgiRGF5IikgKw0KICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQoIlN0cmVzcyBncm91cCIpKQ0KICAjZ2dwbG90Mjo6YW5ub3RhdGUoInRleHQiLCB4ID0gLTAuMywgeSA9IDAuMywgbGFiZWwgPSAiUCA9IE5TIikgI0FkZCBwLXZhbHVlIGZyb20gYWRvbmlzDQoNCmJldGEuc3RyZXNzLmRheQ0KYGBgDQoNCiNQZXJtYW5vdmENCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQ0KRF9CQyA8LSBwaHlsb3NlcTo6ZGlzdGFuY2UoUFNCLkNTUywgImJyYXkiKQ0KDQphZG9uaXMgPC0gYWRvbmlzMihEX0JDIH4gVGltZXBvaW50ICsgU3RyZXNzX2dyb3VwLCBkYXRhID0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShQU0IuQ1NTKSkpDQoNCmFkb25pcw0KYGBgDQoNClBlcm1hbm92YSAtIHRpbWUgcG9pbnRzIHNlcGFyYXRlbHkNCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcHMgPC0gc3Vic2V0X3NhbXBsZXMoUFNCLkNTUyxEYXk9PSJEYXkgMTAiKQ0KDQpEX0JDIDwtIHBoeWxvc2VxOjpkaXN0YW5jZSgNCiAgcHMsDQogICJicmF5IikNCg0KYWRvbmlzIDwtIGFkb25pczIoRF9CQyB+IFN0cmVzc19ncm91cCwgZGF0YSA9IGRhdGEuZnJhbWUoc2FtcGxlX2RhdGEocHMpKSwgcGVybXV0YXRpb25zID0gOTk5OSkNCg0KYWRvbmlzDQpgYGANCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcHMgPC0gc3Vic2V0X3NhbXBsZXMoUFNCLkNTUyxEYXk9PSJEYXkgMjQiKQ0KDQpEX0JDIDwtIHBoeWxvc2VxOjpkaXN0YW5jZSgNCiAgcHMsDQogICJicmF5IikNCg0KYWRvbmlzIDwtIGFkb25pczIoRF9CQyB+IFN0cmVzc19ncm91cCwgZGF0YSA9IGRhdGEuZnJhbWUoc2FtcGxlX2RhdGEocHMpKSwgcGVybXV0YXRpb25zID0gOTk5OSkNCg0KYWRvbmlzDQpgYGANCg0KIyBEaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIC0gRGVzZXEyDQoNCiMjIERlc2VxIDIgTWFvIHN0eWxlDQogDQojIyMgUnVuIGRlc2VxMg0KDQpgYGB7cix3YXJuaW5nPUYsbWVzc2FnZT1GfQ0KcHMgPC0gUFNCDQpwcyA8LSB0YXhfZ2xvbShwcywgIlNwZWNpZXMiLCBOQXJtID0gRkFMU0UpICNzZWxlY3QgYSBsZXZlbCB0byBjb21wYXJlDQoNCg0KbGlicmFyeShERVNlcTIpDQogIA0KICAjIHJlbW92ZSBhbGwgZXJyb3IgdGF4YQ0KICBwcy5kcyA8LSBwaHlsb3NlcV90b19kZXNlcTIocHMsIH5TdHJlc3NfZ3JvdXAgKyBUaW1lcG9pbnQpDQogICMgc29sdmUgcm93cyB3aXRob3V0IGEgemVybywgZGVzZXEgbmVlZCB0byBjYWxjdWxhdGUgdGhlIGdlb21ldHJpYyB6ZXJvLCANCiAgY3RzIDwtIGNvdW50cyhwcy5kcykNCiAgZ2VvTWVhbnMgPC0gYXBwbHkoY3RzLCAxLCBmdW5jdGlvbihyb3cpIGlmIChhbGwocm93ID09IDApKSAwIGVsc2UgZXhwKG1lYW4obG9nKHJvd1tyb3cgIT0gMF0pKSkpDQogIGRkcyA8LSBlc3RpbWF0ZVNpemVGYWN0b3JzKHBzLmRzLCBnZW9NZWFucz1nZW9NZWFucykNCiAgcHMuZHMgPC0gIERFU2VxMjo6REVTZXEoZGRzLCB0ZXN0PSJXYWxkIiwgZml0VHlwZT0icGFyYW1ldHJpYyIpDQogICMgcmVzdWx0DQogIHJlcyA9IHJlc3VsdHMocHMuZHMsIGNvb2tzQ3V0b2ZmID0gRkFMU0UpDQogIHNpZ3RhYiA9IHJlcw0KICBzaWd0YWIgPSBjYmluZChhcyhzaWd0YWIsICJkYXRhLmZyYW1lIiksIGFzKHRheF90YWJsZShwcylbcm93bmFtZXMoc2lndGFiKSwgXSwgIm1hdHJpeCIpKQ0KICBoZWFkKHNpZ3RhYikNCmBgYCAgDQoNCiMjIyBWb2xjYW5vDQoNCmBgYHtyfQ0KRW5oYW5jZWRWb2xjYW5vOjpFbmhhbmNlZFZvbGNhbm8oc2lndGFiLA0KICAgIGxhYiA9ICBzdWIoIl5bXl9dKl8iLCAiIiwgcm93bmFtZXMocmVzKSksDQogICAgeCA9ICdsb2cyRm9sZENoYW5nZScsDQogICAgeSA9ICdwdmFsdWUnLA0KICAgIHBDdXRvZmYgPSAwLjA1LA0KICAgIEZDY3V0b2ZmID0gMC41KQ0KDQpgYGANCg0KIyMjIExvZy1mb2xkIGNoYW5nZSBib3hwbG90DQoNCmBgYHtyLHdhcm5pbmc9RixtZXNzYWdlPUZ9DQoNCiMgU2VsZWN0IHNpZ25pZmljYW50IEFTVnMNCg0KdGFiIDwtIHN1YnNldChzaWd0YWIsIHBhZGogPCAwLjA1KQ0KDQpPVFUgPC0gdW5pcXVlKHRhYikNCg0KIyMNCnBzLnJlbCA8LSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhQU0IsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKjEwMCkNCnBzLnJlbC5zaWcgPC0gcHJ1bmVfdGF4YShjb2xuYW1lcyhvdHVfdGFibGUocHMucmVsKSkgJWluJSByb3duYW1lcyhPVFUpICwgcHMucmVsKQ0KIyMgYXQgbGVhc3QgMSUgcmVsYXRpdmUgYWJ1bmRhbmNlIGFwcGVhcmFuY2UgaW4gMSUgc2FtcGxlcw0KbWF0IDwtIGFzLm1hdHJpeChvdHVfdGFibGUocHMucmVsLnNpZykpDQpzcGVjaWVzMmtlZXAgPC0gY29sbmFtZXMobWF0KVtyb3dTdW1zKG1hdD49MikvbGVuZ3RoKGNvbG5hbWVzKG1hdCkpPiAwLjFdDQpzcGVjaWVzMmtlZXAgPC0gc3BlY2llczJrZWVwWyFpcy5uYShzcGVjaWVzMmtlZXApXQ0Kc2lndGFiLnAucHJldiA8LSB0YWJbc3BlY2llczJrZWVwLF0NCg0Kc2lndGFiZ2VuID0gc3Vic2V0KHNpZ3RhYi5wLnByZXYsICFpcy5uYShHZW51cykpDQoNCiMgUGh5bHVtIG9yZGVyDQp4ID0gdGFwcGx5KHNpZ3RhYmdlbiRsb2cyRm9sZENoYW5nZSwgc2lndGFiZ2VuJFBoeWx1bSwgZnVuY3Rpb24oeCkgbWF4KHgpKQ0KeCA9IHNvcnQoeCwgVFJVRSkNCnNpZ3RhYmdlbiRQaHlsdW0gPSBmYWN0b3IoYXMuY2hhcmFjdGVyKHNpZ3RhYmdlbiRQaHlsdW0pLCBsZXZlbHM9bmFtZXMoeCkpDQojIEdlbnVzIG9yZGVyDQp4ID0gdGFwcGx5KHNpZ3RhYmdlbiRsb2cyRm9sZENoYW5nZSwgc2lndGFiZ2VuJEdlbnVzLCBmdW5jdGlvbih4KSBtYXgoeCkpDQp4ID0gc29ydCh4LCBUUlVFKQ0Kc2lndGFiZ2VuJEdlbnVzID0gZmFjdG9yKGFzLmNoYXJhY3RlcihzaWd0YWJnZW4kR2VudXMpLCBsZXZlbHM9bmFtZXMoeCkpDQoNCmdncGxvdChzaWd0YWJnZW4sIGFlcyh5PUdlbnVzLCB4PWxvZzJGb2xkQ2hhbmdlLCBjb2xvcj1QaHlsdW0pKSArIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjAsIGNvbG9yID0gImdyYXkiLCBzaXplID0gMC41KSArDQogIGdlb21fYm94cGxvdCgpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gLTkwLCBoanVzdCA9IDAsIHZqdXN0PTAuNSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbF9maWxbMzo0XSkNCg0KZGVzZXEyLmxvZzJmb2xkLmJveCA8LSBnZ3Bsb3Qoc2lndGFiZ2VuLCBhZXMoeT1HZW51cywgeD1sb2cyRm9sZENoYW5nZSwgY29sb3I9RmFtaWx5KSkgKyANCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC4wLCBjb2xvciA9ICJncmF5Iiwgc2l6ZSA9IDAuNSkgKw0KICBnZW9tX2JveHBsb3QoKSArIA0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC05MCwgaGp1c3QgPSAwLCB2anVzdD0wLjUpLA0KICAgICAgICAjcGxvdC5tYXJnaW4gPSBtYXJnaW4oMiwgMCwgMCwgMCwgImNtIikNCiAgICAgICAgKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xfZmlsKSArDQogIHlsYWIoIkFTViBnZW51cyIpICsNCiAgZ2d0aXRsZSgiXFUyMTkwIENvbnRyb2xzICAgICAgICBIUyBcVTIxOTIiKQ0KDQpkZXNlcTIubG9nMmZvbGQuYm94DQpgYGANCg0KDQojIyMgSGVhdG1hcA0KICANCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0gIA0KICB0aGVtZV9zZXQodGhlbWVfYncoKSkNCiAgDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUgPC0gZnVuY3Rpb24ocGFsbmFtZSA9ICJTZXQxIiwgLi4uKSB7DQogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9IHBhbG5hbWUsIC4uLikNCiAgfQ0KICANCiAgDQp0YWIgPC0gc3Vic2V0KHNpZ3RhYiwgcGFkaiA8IDAuMDUpDQoNCk9UVSA8LSB1bmlxdWUodGFiKQ0KDQpwcy5yZWwgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMocHMsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKjEwMCkNCnBzLnJlbC5zaWcgPC0gcHJ1bmVfdGF4YShjb2xuYW1lcyhvdHVfdGFibGUocHMucmVsKSkgJWluJSByb3duYW1lcyhPVFUpICwgcHMucmVsKQ0KDQojc2VsZWN0IHRoZSByZWwtYWJ1biA+IDAuMSUNCg0KIyBhdCBsZWFzdCAxJSByZWxhdGl2ZSBhYnVuZGFuY2UgYXBwZWFyYW5jZSBpbiA1JSBzYW1wbGVzDQptYXQgPC0gYXMubWF0cml4KG90dV90YWJsZShwcy5yZWwuc2lnKSkNCnNwZWNpZXMya2VlcCA8LSBjb2xuYW1lcyhtYXQpW3Jvd1N1bXMobWF0Pj0xKS9sZW5ndGgoY29sbmFtZXMobWF0KSk+IDAuMV0NCnNwZWNpZXMya2VlcA0KcHMucmVsLnNpZyA8LSBwcnVuZV90YXhhKHNwZWNpZXMya2VlcCxwcy5yZWwuc2lnKQ0KDQpvdHVfYWJ1bl9zZWxlY3QgPC0gZGF0YS5mcmFtZShvdHVfdGFibGUocHMucmVsLnNpZyksIGNoZWNrLm5hbWVzID0gRikNCg0KI2ltcG9ydCByZWxhdmFudCBtZXRhZGF0YQ0KbWV0YWRhdGEgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwcy5yZWwuc2lnKSkNCnRheC5jbGVhbiA8LSBkYXRhLmZyYW1lKHRheF90YWJsZShwcy5yZWwuc2lnKSkNCg0KDQojIGNyZWF0ZSBhIHZhcmlhYmxlIHRvIGRlZmluZSB0aGUgc3ViZ3JvdXANCiMgb3JkZXIgdGhlIG1hdHJpeCBieSB0aGUgc3ViZ3JvdXANCiMgbWV0YWRhdGEkVHJlYXRtZW50IDwtIGZhY3RvcihtZXRhZGF0YSRUcmVhdG1lbnQsIGxldmVscyA9IGdyb3VwcykNCiMgbWV0YV9vcmRlciA8LSBtZXRhZGF0YVtvcmRlcihtZXRhZGF0YSRUcmVhdG1lbnQpLF0NCg0KIyAjIHJlX29yZGVyIHRoZSBjb2wNCiMgbWF0IDwtIG90dV9hYnVuX3NlbGVjdA0KIyBtYXQgPC0gYXMubWF0cml4KG1hdFsscm93bmFtZXMobWV0YV9vcmRlcildKQ0KDQpiYXNlX21lYW4gPSByb3dNZWFucyhtYXQpDQptYXRfc2NhbGVkID0gdChzY2FsZSh0KG1hdCkpKQ0KDQojIGNhbGN1bGF0ZSBoZWF0bWFwIGFubm90YXRpb24NCnRheF9oZWF0bWFwIDwtIHRheC5jbGVhbltjb2xuYW1lcyhtYXRfc2NhbGVkKSxdDQoNCnRheF9oZWF0bWFwJHNpZ24gPC0gc2FwcGx5KHJvd25hbWVzKHRheF9oZWF0bWFwKSwgZnVuY3Rpb24oeCkgaWZlbHNlKHggJWluJSByb3duYW1lcyhzaWd0YWIpLCIqIiwibnMiKSkNCg0KaW5kZXggPC0gbWF0Y2gocm93bmFtZXModGF4X2hlYXRtYXApLCByb3duYW1lcyh0YWIpKQ0KaW5kZXgNCnRheF9oZWF0bWFwJHBfdmFsIDwtIHRhYiRwYWRqW2luZGV4XQ0KDQp0YXhfaGVhdG1hcCA8LSB0YXhfaGVhdG1hcFtvcmRlcih0YXhfaGVhdG1hcCRwX3ZhbCksXQ0KDQptYXgoYygtbG9nMTAodGF4X2hlYXRtYXAkcF92YWwpKSkNCg0KDQojIG15X3BhbGV0dGUgPC0gYygiZGFya2JsdWUiLCAiZGFya2dvbGRlbnJvZDEiLCAiZGFya3NlYWdyZWVuIiwgImRhcmtvcmNoaWQiLCAiZGFya29saXZlZ3JlZW4xIiwgImxpZ2h0c2t5Ymx1ZSIsICJkYXJrZ3JlZW4iLA0KIyAgICAgICAgICAgICAgICAgImRlZXBwaW5rIiwgImtoYWtpMiIsICJmaXJlYnJpY2siLCAiYnJvd24xIiwgImRhcmtvcmFuZ2UxIiwgImN5YW4xIiwgInJveWFsYmx1ZTQiLCAiZGFya3NhbG1vbiIsICJkYXJrYmx1ZSIsIA0KIyAgICAgICAgICAgICAgICAgInJveWFsYmx1ZTQiLCAiZG9kZ2VyYmx1ZTMiLCAic3RlZWxibHVlMSIsICJsaWdodHNreWJsdWUiLCAiZGFya3NlYWdyZWVuIiwgImRhcmtnb2xkZW5yb2QxIiwgImRhcmtzZWFncmVlbiIsIA0KIyAgICAgICAgICAgICAgICAgImRhcmtvcmNoaWQiLCAiZGFya29saXZlZ3JlZW4xIiwgImJyb3duMSIsICJkYXJrb3JhbmdlMSIsICJjeWFuMSIsICJkYXJrZ3JleSIsICJkYXJrYmx1ZSIsICJkYXJrZ29sZGVucm9kMSIsIA0KIyAgICAgICAgICAgICAgICAgImRhcmtzZWFncmVlbiIsICJkYXJrb3JjaGlkIiwgImRhcmtvbGl2ZWdyZWVuMSIsICJsaWdodHNreWJsdWUiLCAiZGFya2dyZWVuIiwgImRlZXBwaW5rIiwgImtoYWtpMiIsIA0KIyAgICAgICAgICAgICAgICAgImZpcmVicmljayIsICJicm93bjEiLCAiZGFya29yYW5nZTEiLCAiY3lhbjEiLCAicm95YWxibHVlNCIsICJkYXJrc2FsbW9uIiwgImRhcmtibHVlIiwgInJveWFsYmx1ZTQiLCANCiMgICAgICAgICAgICAgICAgICJkb2RnZXJibHVlMyIsICJzdGVlbGJsdWUxIiwgImxpZ2h0c2t5Ymx1ZSIsICJkYXJrc2VhZ3JlZW4iLCAiZGFya2dvbGRlbnJvZDEiLCAiZGFya3NlYWdyZWVuIiwgImRhcmtvcmNoaWQiLCANCiMgICAgICAgICAgICAgICAgICJkYXJrb2xpdmVncmVlbjEiLCAiYnJvd24xIiwgImRhcmtvcmFuZ2UxIiwgImN5YW4xIiwgImRhcmtncmV5IikNCg0KbXlfcGFsZXR0ZSA8LSByZXAoY29sX2ZpbCw1KQ0KDQojIGFkanVzdCB0YXhfaGVhdG1hcCBnZW51cyBhbmQgc3BlY2llcywgcGFzdGV1cmVsbGENCnRheF9oZWF0bWFwJEdlbnVzIDwtIGFzLmNoYXJhY3Rlcih0YXhfaGVhdG1hcCRHZW51cykNCnRheF9oZWF0bWFwJFNwZWNpZXMgPC0gYXMuY2hhcmFjdGVyKHRheF9oZWF0bWFwJFNwZWNpZXMpDQoNCmxpYnJhcnkoY2lyY2xpemUpDQoNCnRheF9oZWF0bWFwIDwtIHRheF9oZWF0bWFwW29yZGVyKHJvd25hbWVzKG1hdF9zY2FsZWQpKSxdDQpjb21tb25fcm93cyA8LSBpbnRlcnNlY3Qocm93bmFtZXModGF4X2hlYXRtYXApLCBjb2xuYW1lcyhtYXRfc2NhbGVkKSkNCnRheF9oZWF0bWFwIDwtIHRheF9oZWF0bWFwW2NvbW1vbl9yb3dzLCBdDQptYXRfc2NhbGVkIDwtIHQobWF0X3NjYWxlZFssY29tbW9uX3Jvd3NdKQ0KI3Jvd25hbWVzKHRheF9oZWF0bWFwKTwtIHRheF9oZWF0bWFwJFNwZWNpZXMNCnJvd25hbWVzKG1hdF9zY2FsZWQpIDwtcm93bmFtZXModGF4X2hlYXRtYXApDQoNCiMjIE9yZGVyIGJ5IHN0cmVzcyBncm91cA0KIyBtZXRhIDwtIG1ldGEgJT4lIGRhdGEuZnJhbWUgJT4lIGFycmFuZ2UoU3RyZXNzX2dyb3VwKQ0KIyBtYXRfc2NhbGVkIDwtIG1hdF9zY2FsZWRbLHJvd25hbWVzKG1ldGEpXQ0KDQpwbG90IDwtIG1hdF9zY2FsZWQNCmdlbnVzIDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIodGF4X2hlYXRtYXAkR2VudXMpKQ0KI2dlbnVzX2NvbCA8LSBjb2xvclJhbXBQYWxldHRlKG15X3BhbGV0dGUpKGxlbmd0aChnZW51cykpIw0KZ2VudXNfY29sIDwtIG15X3BhbGV0dGVbMTpsZW5ndGgoZ2VudXMpXQ0KbmFtZXMoZ2VudXNfY29sKSA8LSBnZW51cw0KDQpwdmFsdWVfY29sX2Z1biA9IGNpcmNsaXplOjpjb2xvclJhbXAyKGMoMSwwLjEsMC4wNSksIGMoInJlZCIsICJ3aGl0ZSIsICJsaWdodHNlYWdyZWVuIikpDQoNCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApDQoNCmhhX3JvdyA8LSBIZWF0bWFwQW5ub3RhdGlvbigNCiAgIydDb250cm9sIHZzIFN0cmVzcyc9YW5ub19zaW1wbGUoLWxvZzEwKHRheF9oZWF0bWFwJHBfdmFsKSxjb2wgPSBwdmFsdWVfY29sX2Z1biwgcGNoID0gbmFfaWYodGF4X2hlYXRtYXAkc2lnbiwibnMiKSwgZ3AgPSBncGFyKGNpcmNsaXplOjpmb250c2l6ZSgxKSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdlbnVzPWFubm9fc2ltcGxlKHRheF9oZWF0bWFwJEdlbnVzLCBjb2wgPSBnZW51c19jb2wpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gInJvdyIpDQoNCmhhX3Jvd190eHQgPC0gcm93QW5ub3RhdGlvbihsYWJlbHMgPSBhbm5vX3RleHQocm93bmFtZXModGF4X2hlYXRtYXApLCB3aGljaCA9ICJyb3ciLGdwPWdwYXIoZm9udHNpemU9MTAsIGZhY2U9ICJpdGFsaWMiKSkpDQoNCg0KDQoNCmhhX2NvbCA9IEhlYXRtYXBBbm5vdGF0aW9uKCdTdHJlc3MgZ3JvdXAnPW1ldGEkU3RyZXNzX2dyb3VwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdCgnU3RyZXNzIGdyb3VwJz1jKCJTdHJlc3MiPWNvbF9maWxbMl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb250cm9sIj1jb2xfZmlsWzFdKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICMgLCB3aWR0aCA9IG1heF90ZXh0X3dpZHRoKHVubGlzdCh0ZXh0X2xpc3QpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KDQoNCg0KSGlzdCA8LSBDb21wbGV4SGVhdG1hcDo6cGhlYXRtYXAocGxvdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLCBjbHVzdGVyX3Jvd3MgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0iWi1zY29yZSIsIGNvbD1jaXJjbGl6ZTo6Y29sb3JSYW1wMihjKC0yLCAwLCAyKSwgYygiZG9kZ2VyYmx1ZTQiLCAid2hpdGUiLCJkZWVwcGluazMiKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfYW5ub3RhdGlvbiA9IGhhX2NvbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZnRfYW5ub3RhdGlvbiA9IGhhX3JvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpZ2h0X2Fubm90YXRpb24gPSBoYV9yb3dfdHh0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChsZWdlbmRfZGlyZWN0aW9uID0gImhvcml6b250YWwiKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KSGlzdA0KDQojIGRlZmluZSB0aGUgdHdvIGxlZ2VuZA0KbGdkX2dlbnVzID0gTGVnZW5kKHRpdGxlID0gIkdlbnVzIiwgbGVnZW5kX2dwID0gZ3BhcihmaWxsID0gZ2VudXNfY29sKSxsYWJlbHMgPSBnZW51cywgbmNvbCA9IDMpDQoNCmxnZF9zaWcgPSBMZWdlbmQodGl0bGU9ICIgIiwgcGNoID0gIioiLCB0eXBlID0gInBvaW50cyIsIGxhYmVscyA9ICJwIDwgMC4wNSIpDQoNCg0KcHZhbHVlX2NvbF9mdW4gPSBjb2xvclJhbXAyKGMoMSwwLjEsMC4wNSksIGMoInJlZCIsICJ3aGl0ZSIsICJsaWdodHNlYWdyZWVuIikpDQoNCg0KDQpsZ2RfcHZhbHVlID0gTGVnZW5kKHRpdGxlID0gInAgdmFsdWUiLA0KICAgICAgICAgICAgICAgICAgICBjb2xfZnVuICA9IHB2YWx1ZV9jb2xfZnVuLA0KICAgICAgICAgICAgICAgICAgICBhdCA9IGMoMCwgMSwgMiksDQogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjEiLCIwLjEiLCIwLjA1IiksDQogICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpDQoNCnBfRGVzZXFfaGVhdG1hcCA8LWRyYXcoSGlzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfbGlzdD1saXN0KGxnZF9nZW51cw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2xnZF9wdmFsdWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjbGdkX3NpZw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iLCBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpIA0KDQpwX0Rlc2VxX2hlYXRtYXAgDQoNCmBgYA0KDQoNCiMjIFN0cmVzcyBncm91cA0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQojU2V0dGluZ3MgZm9yIGN1dG9mZiB2YWx1ZXMgZm9yIHBsb3R0aW5nDQphbHBoYSA9IDAuNSAjbWluaW11bSBwLXZhbHVlDQpiZXRhID0gMS41I21pbmltdW0gbG9nLWZvbGQgZGlmZmVyZW5jZSANCg0KcHMgPC0gUFNCDQpwc0BvdHVfdGFibGUgPC0gcHNAb3R1X3RhYmxlICsgMQ0KDQpkaWFnZGRzID0gcGh5bG9zZXFfdG9fZGVzZXEyKHBzLCB+IFN0cmVzc19ncm91cCkNCmRpYWdkZHMgPSBERVNlcTI6OkRFU2VxKGRpYWdkZHMsIHRlc3Q9IldhbGQiLCBmaXRUeXBlPSJwYXJhbWV0cmljIikNCg0KcmVzID0gREVTZXEyOjpyZXN1bHRzKGRpYWdkZHMsIGNvb2tzQ3V0b2ZmID0gRkFMU0UpDQoNCnNpZ3RhYiA9IHJlc1t3aGljaChyZXMkcGFkaiA8IGFscGhhICYgYWJzKHJlcyRsb2cyRm9sZENoYW5nZSkgPiBiZXRhKSxdICNTZWxlY3QgdmFsdWVzIGZyb20gcmVzdWx0cyBmaWxlIHdpdGggYWRqIHAgdmFsdWVzPmFscGhhIEFORCBsb2cyZm9sZCBjYWhuZ2U+YmV0YQ0Kc2lndGFiID0gY2JpbmQoYXMoc2lndGFiLCAiZGF0YS5mcmFtZSIpLCBhcy5tYXRyaXgodGF4X3RhYmxlKFBTQilbcm93bmFtZXMoc2lndGFiKSwgXSkpDQojaGVhZChzaWd0YWIpDQoNCiNQbG90dGluZyAtIGdlbnVzDQojIE9yZGVyIG9yZGVyIGJhc2VkIG9uIGFidW5kYW5jZSANCnggPSB0YXBwbHkoc2lndGFiJGxvZzJGb2xkQ2hhbmdlLCBzaWd0YWIkT3JkZXIsIGZ1bmN0aW9uKHgpIG1heCh4KSkNCnggPSBzb3J0KHgsIFRSVUUpDQpzaWd0YWIkT3JkZXIgPSBmYWN0b3IoYXMuY2hhcmFjdGVyKHNpZ3RhYiRPcmRlciksIGxldmVscz1uYW1lcyh4KSkNCiMgR2VudXMgb3JkZXIgYmFzZWQgb24gYWJ1bmRhbmNlIA0KeCA9IHRhcHBseShzaWd0YWIkbG9nMkZvbGRDaGFuZ2UsIHNpZ3RhYiRHZW51cywgZnVuY3Rpb24oeCkgbWF4KHgpKQ0KeCA9IHNvcnQoeCwgVFJVRSkNCnNpZ3RhYiRHZW51cyA9IGZhY3Rvcihhcy5jaGFyYWN0ZXIoc2lndGFiJEdlbnVzKSwgbGV2ZWxzPW5hbWVzKHgpKQ0KDQpkaWZmcGxvdCA8LSBnZ3Bsb3Qoc2lndGFiLCBhZXMoeD1HZW51cywgeT1sb2cyRm9sZENoYW5nZSwgY29sb3I9T3JkZXIpKSArIGdlb21fcG9pbnQoc2l6ZT02KSArIA0KICBzY2FsZV9jb2xvdXJfamNvKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC05MCwgaGp1c3QgPSAwLCB2anVzdD0wLjUpKSsNCiAgZ2d0aXRsZSgiRGlmZmVyZW50aWFsIGFidW5kYW5jZSIpDQoNCg0KIyNIZWF0bWFwIG9mIGRpZmZlcmVudGlhbGx5IGFidW5kYW50IHNwZWNpZXMNCg0KI1BTQi5kaWZmIDwtIG1lcmdlX3BoeWxvc2VxKHN1YnNldChvdHVfdGFibGUoUFNCKSwgcm93bmFtZXMob3R1X3RhYmxlKFBTQikpICVpbiUgcm93bmFtZXMoc2lndGFiKSksdGF4X3RhYmxlKFBTQiksIHNhbXBsZV9kYXRhKFBTQikpDQoNClBTQi5yZWwgPC0gbWljcm9iaW9tZTo6dHJhbnNmb3JtKFBTQiwgImNvbXBvc2l0aW9uYWwiKQ0KDQpQU0IuZGlmZi5yZWwgPC0gbWVyZ2VfcGh5bG9zZXEocHJ1bmVfdGF4YShyb3duYW1lcyhzaWd0YWIpLFBTQi5yZWwpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheF90YWJsZShQU0IucmVsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfZGF0YShQU0IucmVsKSkNCg0KIyBGb3JtYXQgYmVmb3JlIGNvbnZlcnRpbmcgdG8gYW1wdmlzIG9iamV0DQoNCiMjdHJhbnNwb3NlIG90dSB0YWJsZQ0KUFNCLmRpZmYucmVsQG90dV90YWJsZSA8LSB0KFBTQi5kaWZmLnJlbEBvdHVfdGFibGUpDQoNCmFtcHZpczJfUFNCLmRpZmYucmVsIDwtIGFtcF9sb2FkKFBTQi5kaWZmLnJlbCkgI0NvbnZlcnQgcGh5bG9zZXEgdG8gYW1wdmlzMiBvYmplY3QNCg0KYW1wdmlzMl9QU0IuZGlmZi5yZWwkYWJ1bmQgPC0gYW1wdmlzMl9QU0IuZGlmZi5yZWwkYWJ1bmQqMTAwICNNdWx0aXBseSByZWxhdGl2ZSBhYnVuZGFuY2UgYnkgMTAwIGZvciByZWFkIHBlcmNlbnRhZ2UNCg0KYW1wX2hlYXRtYXAoYW1wdmlzMl9QU0IuZGlmZi5yZWwsDQogICAgICAgICAgICBncm91cF9ieSA9ICJTdHJlc3NfZ3JvdXAiLA0KICAgICAgICAgICAgdGF4X2FnZ3JlZ2F0ZSA9ICJHZW51cyIsDQogICAgICAgICAgICB0YXhfc2hvdyA9IDE1LA0KICAgICAgICAgICAgbm9ybWFsaXNlID0gRkFMU0UsDQogICAgICAgICAgICB0YXhfZW1wdHkgPSAiT1RVIiwNCiAgICAgICAgICAgIHRheF9hZGQgPSAiRmFtaWx5IikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBnZ3RpdGxlKCJEaWZmZXJlbnRpYWxseSBhYnVuZGFudCBnZW5lcmEgYnkgZ3JvdXAiKQ0KDQphbXBfaGVhdG1hcChhbXB2aXMyX1BTQi5kaWZmLnJlbCwNCiAgICAgICAgICAgIGdyb3VwX2J5ID0gIlN0cmVzc19ncm91cCIsDQogICAgICAgICAgICB0YXhfYWdncmVnYXRlID0gIlNwZWNpZXMiLA0KICAgICAgICAgICAgdGF4X3Nob3cgPSAxNSwNCiAgICAgICAgICAgIG5vcm1hbGlzZSA9IEZBTFNFLA0KICAgICAgICAgICAgdGF4X2VtcHR5ID0gIk9UVSIsDQogICAgICAgICAgICB0YXhfYWRkID0gIkdlbnVzIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBnZ3RpdGxlKCJEaWZmZXJlbnRpYWxseSBhYnVuZGFudCBnZW5lcmEgYnkgZ3JvdXAiKQ0KDQpgYGANCg0KIyMgVGltZXBvaW50DQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCiNTZXR0aW5ncyBmb3IgY3V0b2ZmIHZhbHVlcyBmb3IgcGxvdHRpbmcNCmFscGhhID0gMC4yICNtaW5pbXVtIHAtdmFsdWUNCmJldGEgPSAyICNtaW5pbXVtIGxvZy1mb2xkIGRpZmZlcmVuY2UgDQoNCnBzIDwtIFBTQg0KDQpkaWFnZGRzID0gcGh5bG9zZXFfdG9fZGVzZXEyKHBzLCB+IFRpbWVwb2ludCkNCmRpYWdkZHMgPSBERVNlcTI6OkRFU2VxKGRpYWdkZHMsIHRlc3Q9IldhbGQiLCBmaXRUeXBlPSJwYXJhbWV0cmljIikNCg0KcmVzID0gREVTZXEyOjpyZXN1bHRzKGRpYWdkZHMsIGNvb2tzQ3V0b2ZmID0gRkFMU0UpDQoNCnNpZ3RhYiA9IHJlc1t3aGljaChyZXMkcGFkaiA8IGFscGhhICYgYWJzKHJlcyRsb2cyRm9sZENoYW5nZSkgPiBiZXRhKSxdICNTZWxlY3QgdmFsdWVzIGZyb20gcmVzdWx0cyBmaWxlIHdpdGggYWRqIHAgdmFsdWVzPmFscGhhIEFORCBsb2cyZm9sZCBjYWhuZ2U+YmV0YQ0Kc2lndGFiID0gY2JpbmQoYXMoc2lndGFiLCAiZGF0YS5mcmFtZSIpLCBhcy5tYXRyaXgodGF4X3RhYmxlKFBTQilbcm93bmFtZXMoc2lndGFiKSwgXSkpDQojaGVhZChzaWd0YWIpDQoNCiNQbG90dGluZyAtIGdlbnVzDQojIE9yZGVyIG9yZGVyIGJhc2VkIG9uIGFidW5kYW5jZSANCnggPSB0YXBwbHkoc2lndGFiJGxvZzJGb2xkQ2hhbmdlLCBzaWd0YWIkT3JkZXIsIGZ1bmN0aW9uKHgpIG1heCh4KSkNCnggPSBzb3J0KHgsIFRSVUUpDQpzaWd0YWIkT3JkZXIgPSBmYWN0b3IoYXMuY2hhcmFjdGVyKHNpZ3RhYiRPcmRlciksIGxldmVscz1uYW1lcyh4KSkNCiMgR2VudXMgb3JkZXIgYmFzZWQgb24gYWJ1bmRhbmNlIA0KeCA9IHRhcHBseShzaWd0YWIkbG9nMkZvbGRDaGFuZ2UsIHNpZ3RhYiRHZW51cywgZnVuY3Rpb24oeCkgbWF4KHgpKQ0KeCA9IHNvcnQoeCwgVFJVRSkNCnNpZ3RhYiRHZW51cyA9IGZhY3Rvcihhcy5jaGFyYWN0ZXIoc2lndGFiJEdlbnVzKSwgbGV2ZWxzPW5hbWVzKHgpKQ0KDQpkaWZmcGxvdCA8LSBnZ3Bsb3Qoc2lndGFiLCBhZXMoeD1HZW51cywgeT1sb2cyRm9sZENoYW5nZSwgY29sb3I9T3JkZXIpKSArIGdlb21fcG9pbnQoc2l6ZT02KSArIA0KICBzY2FsZV9jb2xvdXJfamNvKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC05MCwgaGp1c3QgPSAwLCB2anVzdD0wLjUpKSsNCiAgZ2d0aXRsZSgiRGlmZmVyZW50aWFsIGFidW5kYW5jZSBieSBHZXN0YXRpb25hbCBhZ2UiKQ0KDQoNCiMjSGVhdG1hcCBvZiBkaWZmZXJlbnRpYWxseSBhYnVuZGFudCBzcGVjaWVzDQoNCiNQU0IuZGlmZiA8LSBtZXJnZV9waHlsb3NlcShzdWJzZXQob3R1X3RhYmxlKFBTQiksIHJvd25hbWVzKG90dV90YWJsZShQU0IpKSAlaW4lIHJvd25hbWVzKHNpZ3RhYikpLHRheF90YWJsZShQU0IpLCBzYW1wbGVfZGF0YShQU0IpKQ0KDQpQU0IucmVsIDwtIG1pY3JvYmlvbWU6OnRyYW5zZm9ybShwcywgImNvbXBvc2l0aW9uYWwiKQ0KDQpQU0IuZGlmZi5yZWwgPC0gbWVyZ2VfcGh5bG9zZXEocHJ1bmVfdGF4YShyb3duYW1lcyhzaWd0YWIpLFBTQi5yZWwpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheF90YWJsZShQU0IucmVsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfZGF0YShQU0IucmVsKSkNCg0KIyBGb3JtYXQgYmVmb3JlIGNvbnZlcnRpbmcgdG8gYW1wdmlzIG9iamV0DQoNCiMjdHJhbnNwb3NlIG90dSB0YWJsZQ0KUFNCLmRpZmYucmVsQG90dV90YWJsZSA8LSB0KFBTQi5kaWZmLnJlbEBvdHVfdGFibGUpDQoNCmFtcHZpczJfUFNCLmRpZmYucmVsIDwtIGFtcF9sb2FkKFBTQi5kaWZmLnJlbCkgI0NvbnZlcnQgcGh5bG9zZXEgdG8gYW1wdmlzMiBvYmplY3QNCg0KYW1wdmlzMl9QU0IuZGlmZi5yZWwkYWJ1bmQgPC0gYW1wdmlzMl9QU0IuZGlmZi5yZWwkYWJ1bmQqMTAwICNNdWx0aXBseSByZWxhdGl2ZSBhYnVuZGFuY2UgYnkgMTAwIGZvciByZWFkIHBlcmNlbnRhZ2UNCg0KYW1wX2hlYXRtYXAoYW1wdmlzMl9QU0IuZGlmZi5yZWwsDQogICAgICAgICAgICBncm91cF9ieSA9ICJUaW1lcG9pbnQiLA0KICAgICAgICAgICAgdGF4X2FnZ3JlZ2F0ZSA9ICJHZW51cyIsDQogICAgICAgICAgICB0YXhfc2hvdyA9IDE1LA0KICAgICAgICAgICAgbm9ybWFsaXNlID0gRkFMU0UsDQogICAgICAgICAgICB0YXhfZW1wdHkgPSAiT1RVIiwNCiAgICAgICAgICAgIHRheF9hZGQgPSAiRmFtaWx5IikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBnZ3RpdGxlKCJEaWZmZXJlbnRpYWxseSBhYnVuZGFudCBnZW5lcmEgYnkgZ3JvdXAiKQ0KDQpgYGANCg0KIyMgU3RyZXNzIGdyb3VwIHdpdGggdGltZSBwb2ludCBhcyBmaXhlZCBlZmZlY3QNCg0KIyMjIEdlbnVzIGxldmVsDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCiNTZXR0aW5ncyBmb3IgY3V0b2ZmIHZhbHVlcyBmb3IgcGxvdHRpbmcNCmFscGhhID0gMC4wNSAjbWluaW11bSBwLXZhbHVlDQpiZXRhID0gMiAjbWluaW11bSBsb2ctZm9sZCBkaWZmZXJlbmNlIA0KDQpwcyA8LSBQU0INCg0KZGlhZ2RkcyA9IHBoeWxvc2VxX3RvX2Rlc2VxMihwcywgfiBTdHJlc3NfZ3JvdXAgKyBUaW1lcG9pbnQpDQpkaWFnZGRzID0gREVTZXEyOjpERVNlcShkaWFnZGRzLCB0ZXN0PSJXYWxkIiwgZml0VHlwZT0icGFyYW1ldHJpYyIpDQoNCnJlcyA9IERFU2VxMjo6cmVzdWx0cyhkaWFnZGRzLCBjb29rc0N1dG9mZiA9IEZBTFNFKQ0KDQpzaWd0YWIgPSByZXNbd2hpY2gocmVzJHBhZGogPCBhbHBoYSAmIGFicyhyZXMkbG9nMkZvbGRDaGFuZ2UpID4gYmV0YSksXSAjU2VsZWN0IHZhbHVlcyBmcm9tIHJlc3VsdHMgZmlsZSB3aXRoIGFkaiBwIHZhbHVlcz5hbHBoYSBBTkQgbG9nMmZvbGQgY2FobmdlPmJldGENCnNpZ3RhYiA9IGNiaW5kKGFzKHNpZ3RhYiwgImRhdGEuZnJhbWUiKSwgYXMubWF0cml4KHRheF90YWJsZShQU0IpW3Jvd25hbWVzKHNpZ3RhYiksIF0pKQ0KI2hlYWQoc2lndGFiKQ0KDQojUGxvdHRpbmcgLSBnZW51cw0KIyBPcmRlciBvcmRlciBiYXNlZCBvbiBhYnVuZGFuY2UgDQp4ID0gdGFwcGx5KHNpZ3RhYiRsb2cyRm9sZENoYW5nZSwgc2lndGFiJE9yZGVyLCBmdW5jdGlvbih4KSBtYXgoeCkpDQp4ID0gc29ydCh4LCBUUlVFKQ0Kc2lndGFiJE9yZGVyID0gZmFjdG9yKGFzLmNoYXJhY3RlcihzaWd0YWIkT3JkZXIpLCBsZXZlbHM9bmFtZXMoeCkpDQojIEdlbnVzIG9yZGVyIGJhc2VkIG9uIGFidW5kYW5jZSANCnggPSB0YXBwbHkoc2lndGFiJGxvZzJGb2xkQ2hhbmdlLCBzaWd0YWIkR2VudXMsIGZ1bmN0aW9uKHgpIG1heCh4KSkNCnggPSBzb3J0KHgsIFRSVUUpDQpzaWd0YWIkR2VudXMgPSBmYWN0b3IoYXMuY2hhcmFjdGVyKHNpZ3RhYiRHZW51cyksIGxldmVscz1uYW1lcyh4KSkNCg0KZGlmZnBsb3QgPC0gZ2dwbG90KHNpZ3RhYiwgYWVzKHg9R2VudXMsIHk9bG9nMkZvbGRDaGFuZ2UsIGNvbG9yPU9yZGVyKSkgKyBnZW9tX3BvaW50KHNpemU9NikgKyANCiAgc2NhbGVfY29sb3VyX2pjbygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAtOTAsIGhqdXN0ID0gMCwgdmp1c3Q9MC41KSkrDQogIGdndGl0bGUoIkRpZmZlcmVudGlhbCBhYnVuZGFuY2UgYnkgR2VzdGF0aW9uYWwgYWdlIikNCg0KDQojI0hlYXRtYXAgb2YgZGlmZmVyZW50aWFsbHkgYWJ1bmRhbnQgc3BlY2llcw0KDQojUFNCLmRpZmYgPC0gbWVyZ2VfcGh5bG9zZXEoc3Vic2V0KG90dV90YWJsZShQU0IpLCByb3duYW1lcyhvdHVfdGFibGUoUFNCKSkgJWluJSByb3duYW1lcyhzaWd0YWIpKSx0YXhfdGFibGUoUFNCKSwgc2FtcGxlX2RhdGEoUFNCKSkNCg0KUFNCLnJlbCA8LSBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0ocHMsICJjb21wb3NpdGlvbmFsIikNCg0KUFNCLmRpZmYucmVsIDwtIG1lcmdlX3BoeWxvc2VxKHBydW5lX3RheGEocm93bmFtZXMoc2lndGFiKSxQU0IucmVsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXhfdGFibGUoUFNCLnJlbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEoUFNCLnJlbCkpDQoNCiMgRm9ybWF0IGJlZm9yZSBjb252ZXJ0aW5nIHRvIGFtcHZpcyBvYmpldA0KDQojI3RyYW5zcG9zZSBvdHUgdGFibGUNClBTQi5kaWZmLnJlbEBvdHVfdGFibGUgPC0gdChQU0IuZGlmZi5yZWxAb3R1X3RhYmxlKQ0KDQphbXB2aXMyX1BTQi5kaWZmLnJlbCA8LSBhbXBfbG9hZChQU0IuZGlmZi5yZWwpICNDb252ZXJ0IHBoeWxvc2VxIHRvIGFtcHZpczIgb2JqZWN0DQoNCmFtcHZpczJfUFNCLmRpZmYucmVsJGFidW5kIDwtIGFtcHZpczJfUFNCLmRpZmYucmVsJGFidW5kKjEwMCAjTXVsdGlwbHkgcmVsYXRpdmUgYWJ1bmRhbmNlIGJ5IDEwMCBmb3IgcmVhZCBwZXJjZW50YWdlDQoNCmFtcF9oZWF0bWFwKGFtcHZpczJfUFNCLmRpZmYucmVsLA0KICAgICAgICAgICAgZ3JvdXBfYnkgPSAiU3RyZXNzX2dyb3VwIiwNCiAgICAgICAgICAgIHRheF9hZ2dyZWdhdGUgPSAiR2VudXMiLA0KICAgICAgICAgICAgdGF4X3Nob3cgPSAxMiwNCiAgICAgICAgICAgIG5vcm1hbGlzZSA9IEZBTFNFLA0KICAgICAgICAgICAgdGF4X2VtcHR5ID0gIk9UVSIsDQogICAgICAgICAgICB0YXhfYWRkID0gIkZhbWlseSIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgZ2d0aXRsZSgiRGlmZmVyZW50aWFsbHkgYWJ1bmRhbnQgZ2VuZXJhIGJ5IGdyb3VwIikNCg0KYGBgDQoNCiMjIyBQaGVhdG1hcA0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQpsaWJyYXJ5KCJwaGVhdG1hcCIpDQphbm5vdGF0aW9uIDwtIGFtcHZpczJfUFNCLmRpZmYucmVsJG1ldGFkYXRhICU+JQ0KICBkcGx5cjo6c2VsZWN0KGMoIlN0cmVzc19ncm91cCIsIlNleF9jaGlsZCIsIkVkdWNhdGlvbl9tb3RoZXIiLCJUaW1lcG9pbnQiKSkNCg0KY29sbmFtZXMoYW5ub3RhdGlvbikgDQoNCmhlYXRfY29sb3JzIDwtIGJyZXdlci5wYWwoNiwgIllsT3JSZCIpDQoNCnBoZWF0bWFwKGFtcHZpczJfUFNCLmRpZmYucmVsJGFidW5kLA0KICAgICAgICAgY29sb3IgPSBoZWF0X2NvbG9ycywgDQogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBULCANCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLA0KICAgICAgICAgYW5ub3RhdGlvbiA9IGFubm90YXRpb24sIA0KICAgICAgICAgYm9yZGVyX2NvbG9yID0gTkEsIA0KICAgICAgICAgZm9udHNpemUgPSAxMCwgDQogICAgICAgICBzY2FsZSA9ICJyb3ciLCANCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDEwLCANCiAgICAgICAgIGhlaWdodCA9IDIwKQ0KYGBgDQoNCiMjIyBTcGVjaWVzIGxldmVsDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCiNTZXR0aW5ncyBmb3IgY3V0b2ZmIHZhbHVlcyBmb3IgcGxvdHRpbmcNCmFscGhhID0gMC4wNSAjbWluaW11bSBwLXZhbHVlDQpiZXRhID0gMiAjbWluaW11bSBsb2ctZm9sZCBkaWZmZXJlbmNlIA0KDQpwcyA8LSBQU0INCg0KZGlhZ2RkcyA9IHBoeWxvc2VxX3RvX2Rlc2VxMihwcywgfiBTdHJlc3NfZ3JvdXAgKyBUaW1lcG9pbnQpDQpkaWFnZGRzID0gREVTZXEyOjpERVNlcShkaWFnZGRzLCB0ZXN0PSJXYWxkIiwgZml0VHlwZT0icGFyYW1ldHJpYyIpDQoNCnJlcyA9IERFU2VxMjo6cmVzdWx0cyhkaWFnZGRzLCBjb29rc0N1dG9mZiA9IEZBTFNFKQ0KDQpzaWd0YWIgPSByZXNbd2hpY2gocmVzJHBhZGogPCBhbHBoYSAmIGFicyhyZXMkbG9nMkZvbGRDaGFuZ2UpID4gYmV0YSksXSAjU2VsZWN0IHZhbHVlcyBmcm9tIHJlc3VsdHMgZmlsZSB3aXRoIGFkaiBwIHZhbHVlcz5hbHBoYSBBTkQgbG9nMmZvbGQgY2FobmdlPmJldGENCnNpZ3RhYiA9IGNiaW5kKGFzKHNpZ3RhYiwgImRhdGEuZnJhbWUiKSwgYXMubWF0cml4KHRheF90YWJsZShQU0IpW3Jvd25hbWVzKHNpZ3RhYiksIF0pKQ0KI2hlYWQoc2lndGFiKQ0KDQojUGxvdHRpbmcgLSBnZW51cw0KIyBPcmRlciBvcmRlciBiYXNlZCBvbiBhYnVuZGFuY2UgDQp4ID0gdGFwcGx5KHNpZ3RhYiRsb2cyRm9sZENoYW5nZSwgc2lndGFiJE9yZGVyLCBmdW5jdGlvbih4KSBtYXgoeCkpDQp4ID0gc29ydCh4LCBUUlVFKQ0Kc2lndGFiJE9yZGVyID0gZmFjdG9yKGFzLmNoYXJhY3RlcihzaWd0YWIkT3JkZXIpLCBsZXZlbHM9bmFtZXMoeCkpDQojIEdlbnVzIG9yZGVyIGJhc2VkIG9uIGFidW5kYW5jZSANCnggPSB0YXBwbHkoc2lndGFiJGxvZzJGb2xkQ2hhbmdlLCBzaWd0YWIkR2VudXMsIGZ1bmN0aW9uKHgpIG1heCh4KSkNCnggPSBzb3J0KHgsIFRSVUUpDQpzaWd0YWIkR2VudXMgPSBmYWN0b3IoYXMuY2hhcmFjdGVyKHNpZ3RhYiRHZW51cyksIGxldmVscz1uYW1lcyh4KSkNCg0KZGlmZnBsb3QgPC0gZ2dwbG90KHNpZ3RhYiwgYWVzKHg9R2VudXMsIHk9bG9nMkZvbGRDaGFuZ2UsIGNvbG9yPU9yZGVyKSkgKyBnZW9tX3BvaW50KHNpemU9NikgKyANCiAgc2NhbGVfY29sb3VyX2pjbygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAtOTAsIGhqdXN0ID0gMCwgdmp1c3Q9MC41KSkrDQogIGdndGl0bGUoIkRpZmZlcmVudGlhbCBhYnVuZGFuY2UgYnkgR2VzdGF0aW9uYWwgYWdlIikNCg0KDQojI0hlYXRtYXAgb2YgZGlmZmVyZW50aWFsbHkgYWJ1bmRhbnQgc3BlY2llcw0KDQojUFNCLmRpZmYgPC0gbWVyZ2VfcGh5bG9zZXEoc3Vic2V0KG90dV90YWJsZShQU0IpLCByb3duYW1lcyhvdHVfdGFibGUoUFNCKSkgJWluJSByb3duYW1lcyhzaWd0YWIpKSx0YXhfdGFibGUoUFNCKSwgc2FtcGxlX2RhdGEoUFNCKSkNCg0KUFNCLnJlbCA8LSBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0ocHMsICJjb21wb3NpdGlvbmFsIikNCg0KUFNCLmRpZmYucmVsIDwtIG1lcmdlX3BoeWxvc2VxKHBydW5lX3RheGEocm93bmFtZXMoc2lndGFiKSxQU0IucmVsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXhfdGFibGUoUFNCLnJlbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEoUFNCLnJlbCkpDQoNCiMgRm9ybWF0IGJlZm9yZSBjb252ZXJ0aW5nIHRvIGFtcHZpcyBvYmpldA0KDQojI3RyYW5zcG9zZSBvdHUgdGFibGUNClBTQi5kaWZmLnJlbEBvdHVfdGFibGUgPC0gdChQU0IuZGlmZi5yZWxAb3R1X3RhYmxlKQ0KDQphbXB2aXMyX1BTQi5kaWZmLnJlbCA8LSBhbXBfbG9hZChQU0IuZGlmZi5yZWwpICNDb252ZXJ0IHBoeWxvc2VxIHRvIGFtcHZpczIgb2JqZWN0DQoNCmFtcHZpczJfUFNCLmRpZmYucmVsJGFidW5kIDwtIGFtcHZpczJfUFNCLmRpZmYucmVsJGFidW5kKjEwMCAjTXVsdGlwbHkgcmVsYXRpdmUgYWJ1bmRhbmNlIGJ5IDEwMCBmb3IgcmVhZCBwZXJjZW50YWdlDQoNCmFtcF9oZWF0bWFwKGFtcHZpczJfUFNCLmRpZmYucmVsLA0KICAgICAgICAgICAgZ3JvdXBfYnkgPSAiU3RyZXNzX2dyb3VwIiwNCiAgICAgICAgICAgIHRheF9hZ2dyZWdhdGUgPSAiU3BlY2llcyIsDQogICAgICAgICAgICB0YXhfc2hvdyA9IDE1LA0KICAgICAgICAgICAgbm9ybWFsaXNlID0gRkFMU0UsDQogICAgICAgICAgICB0YXhfZW1wdHkgPSAiT1RVIiwNCiAgICAgICAgICAgIHRheF9hZGQgPSAiR2VudXMiKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGdndGl0bGUoIkRpZmZlcmVudGlhbGx5IGFidW5kYW50IHNwZWNpZXMgYnkgZ3JvdXAiKQ0KDQpgYGANCg0KIyMgVGltZSBwb2ludCB3aXRoIHN0cmVzcyBncm91cCBhcyBmaXhlZCBlZmZlY3QNCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQ0KI1NldHRpbmdzIGZvciBjdXRvZmYgdmFsdWVzIGZvciBwbG90dGluZw0KYWxwaGEgPSAwLjA1ICNtaW5pbXVtIHAtdmFsdWUNCmJldGEgPSAyICNtaW5pbXVtIGxvZy1mb2xkIGRpZmZlcmVuY2UgDQoNCnBzIDwtIFBTQg0KDQpkaWFnZGRzID0gcGh5bG9zZXFfdG9fZGVzZXEyKHBzLCB+IFRpbWVwb2ludCArIFN0cmVzc19ncm91cCkNCmRpYWdkZHMgPSBERVNlcTI6OkRFU2VxKGRpYWdkZHMsIHRlc3Q9IldhbGQiLCBmaXRUeXBlPSJwYXJhbWV0cmljIikNCg0KcmVzID0gREVTZXEyOjpyZXN1bHRzKGRpYWdkZHMsIGNvb2tzQ3V0b2ZmID0gRkFMU0UpDQoNCnNpZ3RhYiA9IHJlc1t3aGljaChyZXMkcGFkaiA8IGFscGhhICYgYWJzKHJlcyRsb2cyRm9sZENoYW5nZSkgPiBiZXRhKSxdICNTZWxlY3QgdmFsdWVzIGZyb20gcmVzdWx0cyBmaWxlIHdpdGggYWRqIHAgdmFsdWVzPmFscGhhIEFORCBsb2cyZm9sZCBjYWhuZ2U+YmV0YQ0Kc2lndGFiID0gY2JpbmQoYXMoc2lndGFiLCAiZGF0YS5mcmFtZSIpLCBhcy5tYXRyaXgodGF4X3RhYmxlKFBTQilbcm93bmFtZXMoc2lndGFiKSwgXSkpDQojaGVhZChzaWd0YWIpDQoNCiNQbG90dGluZyAtIGdlbnVzDQojIE9yZGVyIG9yZGVyIGJhc2VkIG9uIGFidW5kYW5jZSANCnggPSB0YXBwbHkoc2lndGFiJGxvZzJGb2xkQ2hhbmdlLCBzaWd0YWIkT3JkZXIsIGZ1bmN0aW9uKHgpIG1heCh4KSkNCnggPSBzb3J0KHgsIFRSVUUpDQpzaWd0YWIkT3JkZXIgPSBmYWN0b3IoYXMuY2hhcmFjdGVyKHNpZ3RhYiRPcmRlciksIGxldmVscz1uYW1lcyh4KSkNCiMgR2VudXMgb3JkZXIgYmFzZWQgb24gYWJ1bmRhbmNlIA0KeCA9IHRhcHBseShzaWd0YWIkbG9nMkZvbGRDaGFuZ2UsIHNpZ3RhYiRHZW51cywgZnVuY3Rpb24oeCkgbWF4KHgpKQ0KeCA9IHNvcnQoeCwgVFJVRSkNCnNpZ3RhYiRHZW51cyA9IGZhY3Rvcihhcy5jaGFyYWN0ZXIoc2lndGFiJEdlbnVzKSwgbGV2ZWxzPW5hbWVzKHgpKQ0KDQpkaWZmcGxvdCA8LSBnZ3Bsb3Qoc2lndGFiLCBhZXMoeD1HZW51cywgeT1sb2cyRm9sZENoYW5nZSwgY29sb3I9T3JkZXIpKSArIGdlb21fcG9pbnQoc2l6ZT02KSArIA0KICBzY2FsZV9jb2xvdXJfamNvKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC05MCwgaGp1c3QgPSAwLCB2anVzdD0wLjUpKSsNCiAgZ2d0aXRsZSgiRGlmZmVyZW50aWFsIGFidW5kYW5jZSBieSBHZXN0YXRpb25hbCBhZ2UiKQ0KDQoNCiMjSGVhdG1hcCBvZiBkaWZmZXJlbnRpYWxseSBhYnVuZGFudCBzcGVjaWVzDQoNCiNQU0IuZGlmZiA8LSBtZXJnZV9waHlsb3NlcShzdWJzZXQob3R1X3RhYmxlKFBTQiksIHJvd25hbWVzKG90dV90YWJsZShQU0IpKSAlaW4lIHJvd25hbWVzKHNpZ3RhYikpLHRheF90YWJsZShQU0IpLCBzYW1wbGVfZGF0YShQU0IpKQ0KDQpQU0IucmVsIDwtIG1pY3JvYmlvbWU6OnRyYW5zZm9ybShwcywgImNvbXBvc2l0aW9uYWwiKQ0KDQpQU0IuZGlmZi5yZWwgPC0gbWVyZ2VfcGh5bG9zZXEocHJ1bmVfdGF4YShyb3duYW1lcyhzaWd0YWIpLFBTQi5yZWwpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRheF90YWJsZShQU0IucmVsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfZGF0YShQU0IucmVsKSkNCg0KIyBGb3JtYXQgYmVmb3JlIGNvbnZlcnRpbmcgdG8gYW1wdmlzIG9iamV0DQoNCiMjdHJhbnNwb3NlIG90dSB0YWJsZQ0KUFNCLmRpZmYucmVsQG90dV90YWJsZSA8LSB0KFBTQi5kaWZmLnJlbEBvdHVfdGFibGUpDQoNCmFtcHZpczJfUFNCLmRpZmYucmVsIDwtIGFtcF9sb2FkKFBTQi5kaWZmLnJlbCkgI0NvbnZlcnQgcGh5bG9zZXEgdG8gYW1wdmlzMiBvYmplY3QNCg0KYW1wdmlzMl9QU0IuZGlmZi5yZWwkYWJ1bmQgPC0gYW1wdmlzMl9QU0IuZGlmZi5yZWwkYWJ1bmQqMTAwICNNdWx0aXBseSByZWxhdGl2ZSBhYnVuZGFuY2UgYnkgMTAwIGZvciByZWFkIHBlcmNlbnRhZ2UNCg0KYW1wX2hlYXRtYXAoYW1wdmlzMl9QU0IuZGlmZi5yZWwsDQogICAgICAgICAgICBncm91cF9ieSA9ICJUaW1lcG9pbnQiLA0KICAgICAgICAgICAgdGF4X2FnZ3JlZ2F0ZSA9ICJHZW51cyIsDQogICAgICAgICAgICB0YXhfc2hvdyA9IDE1LA0KICAgICAgICAgICAgbm9ybWFsaXNlID0gRkFMU0UsDQogICAgICAgICAgICB0YXhfZW1wdHkgPSAiT1RVIiwNCiAgICAgICAgICAgIHRheF9hZGQgPSAiRmFtaWx5IikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBnZ3RpdGxlKCJEaWZmZXJlbnRpYWxseSBhYnVuZGFudCBnZW5lcmEgYnkgZ3JvdXAiKQ0KYGBgDQoNCiMgRGlmZmVyZW50aWFsIGFidW5kYW5jZSAtIE1hQXNMaW4yDQoNCiMjIEFTViBsZXZlbA0KDQpgYGB7ciwgZXZhbCA9IEYsIGluY2x1ZGUgPSBGLCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQpsaWJyYXJ5KE1hYXNsaW4yKQ0KDQojIGlucHV0X2RhdGEgPC0gc3lzdGVtLmZpbGUoDQojICAgICAnZXh0ZGF0YScsJ0hNUDJfdGF4b25vbXkudHN2JywgcGFja2FnZT0iTWFhc2xpbjIiKQ0KIyBpbnB1dF9tZXRhZGF0YSA8LXN5c3RlbS5maWxlKA0KIyAgICAgJ2V4dGRhdGEnLCdITVAyX21ldGFkYXRhLnRzdicsIHBhY2thZ2U9Ik1hYXNsaW4yIikNCiMgDQojIGZpdF8gPC0gTWFhc2xpbjIoDQojICAgICBpbnB1dF9kYXRhLCBpbnB1dF9tZXRhZGF0YSwgJ2RlbW9fb3V0cHV0Jw0KIyAgICAgZml4ZWRfZWZmZWN0cyA9IGMoJ2RpYWdub3NpcycsICdkeXNiaW9zaXNub25JQkQnLCdkeXNiaW9zaXNVQycsJ2R5c2Jpb3Npc0NEJywgJ2FudGliaW90aWNzJywgJ2FnZScpLA0KIyAgICAgcmFuZG9tX2VmZmVjdHMgPSBjKCdzaXRlJywgJ3N1YmplY3QnKSwNCiMgICAgIHN0YW5kYXJkaXplID0gRkFMU0UpDQoNCmlucHV0X2RhdGEgPC0gZGF0YS5mcmFtZShvdHVfdGFibGUoUFNCKSkNCiNBZGQgdGF4b25vbXkgdG8gb3R1X3RhYmxlDQp0YXhfY29uY2F0IDwtIGFzLmRhdGEuZnJhbWUoUFNCQHRheF90YWJsZSkgJT4lIA0KICByZXBsYWNlKGlzLm5hKC4pLCAidW5rbm93biIpICU+JQ0KICB0aWR5cjo6dW5pdGUoIlRheG9ub215IiwiRmFtaWx5IjoiU3BlY2llcyIscmVtb3ZlPUZBTFNFKQ0KY29sbmFtZXMoaW5wdXRfZGF0YSkgPC0gdGF4X2NvbmNhdCRUYXhvbm9teQ0KDQppbnB1dF9tZXRhZGF0YSA8LSBkYXRhLmZyYW1lKHNhbXBsZV9kYXRhKFBTQikpDQoNCmZpdF9zdHJlc3NfYW5kX3RpbWUgPC0gTWFhc2xpbjIoDQogICAgaW5wdXRfZGF0YSwgaW5wdXRfbWV0YWRhdGEsICdtYXNzbGluX3N0cmVzc190aW1lcG9pbnQnLA0KICAgIGZpeGVkX2VmZmVjdHMgPSBjKCdTdHJlc3NfZ3JvdXAnLCdUaW1lcG9pbnQnKSwNCiAgICAjcmFuZG9tX2VmZmVjdHMgPSBjKCdTdWJqZWN0X0lEJyksDQogICAgc3RhbmRhcmRpemUgPSBGQUxTRSkNCg0KDQpgYGANCg0KIyMgR2VudXMgbGV2ZWwNCg0KYGBge3IsIGV2YWwgPSBGLCBpbmNsdWRlID0gRiwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcHMgPC0gdGF4X2dsb20oUFNCLCAiR2VudXMiLCBOQXJtID0gRkFMU0UpDQoNCmlucHV0X2RhdGEgPC0gZGF0YS5mcmFtZShvdHVfdGFibGUocHMpKQ0KI0FkZCB0YXhvbm9teSB0byBvdHVfdGFibGUNCnRheF9jb25jYXQgPC0gYXMuZGF0YS5mcmFtZShwc0B0YXhfdGFibGUpICU+JSANCiAgcmVwbGFjZShpcy5uYSguKSwgInVua25vd24iKSAlPiUNCiAgdGlkeXI6OnVuaXRlKCJUYXhvbm9teSIsIkZhbWlseSI6IlNwZWNpZXMiLHJlbW92ZT1GQUxTRSkNCmNvbG5hbWVzKGlucHV0X2RhdGEpIDwtIHRheF9jb25jYXQkVGF4b25vbXkNCg0KaW5wdXRfbWV0YWRhdGEgPC0gZGF0YS5mcmFtZShzYW1wbGVfZGF0YShwcykpDQoNCmZpdF9zdHJlc3NfYW5kX3RpbWUgPC0gTWFhc2xpbjIoDQogICAgaW5wdXRfZGF0YSwgaW5wdXRfbWV0YWRhdGEsICdtYXNzbGluX3N0cmVzc190aW1lcG9pbnRfZ2VudXMnLA0KICAgIGZpeGVkX2VmZmVjdHMgPSBjKCdTdHJlc3NfZ3JvdXAnLCdUaW1lcG9pbnQnKSwNCiAgICAjcmFuZG9tX2VmZmVjdHMgPSBjKCdTdWJqZWN0X0lEJyksDQogICAgc3RhbmRhcmRpemUgPSBGQUxTRSkNCg0KDQpgYGANCg0KIyMgU3BlY2llcyBsZXZlbA0KDQpgYGB7ciwgZXZhbCA9IEYsIGluY2x1ZGUgPSBGLCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQpwcyA8LSB0YXhfZ2xvbShQU0IsICJTcGVjaWVzIiwgTkFybSA9IEZBTFNFKQ0KDQppbnB1dF9kYXRhIDwtIGRhdGEuZnJhbWUob3R1X3RhYmxlKHBzKSkNCiNBZGQgdGF4b25vbXkgdG8gb3R1X3RhYmxlDQp0YXhfY29uY2F0IDwtIGFzLmRhdGEuZnJhbWUocHNAdGF4X3RhYmxlKSAlPiUgDQogIHJlcGxhY2UoaXMubmEoLiksICJ1bmtub3duIikgJT4lDQogIHRpZHlyOjp1bml0ZSgiVGF4b25vbXkiLCJGYW1pbHkiOiJTcGVjaWVzIixyZW1vdmU9RkFMU0UpDQpjb2xuYW1lcyhpbnB1dF9kYXRhKSA8LSB0YXhfY29uY2F0JFRheG9ub215DQoNCmlucHV0X21ldGFkYXRhIDwtIGRhdGEuZnJhbWUoc2FtcGxlX2RhdGEocHMpKQ0KDQpmaXRfc3RyZXNzX2FuZF90aW1lIDwtIE1hYXNsaW4yKA0KICAgIGlucHV0X2RhdGEsIGlucHV0X21ldGFkYXRhLCAnbWFzc2xpbl9zdHJlc3NfdGltZXBvaW50X2dlbnVzX3NwZWNpZXMnLA0KICAgIGZpeGVkX2VmZmVjdHMgPSBjKCdTdHJlc3NfZ3JvdXAnLCdUaW1lcG9pbnQnKSwNCiAgICAjcmFuZG9tX2VmZmVjdHMgPSBjKCdTdWJqZWN0X0lEJyksDQogICAgc3RhbmRhcmRpemUgPSBGQUxTRSkNCg0KDQpgYGANCg0KIyBFZmZlY3Qgc2l6ZQ0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBGLCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQoNCiMjIyMjI0ltcG9ydGluZy1EYXRhDQoNCnN0YW5kZiA9IGZ1bmN0aW9uKHgsIHQ9dG90YWwpIHJvdW5kKHQgKiAoeCAvIHN1bSh4KSkpDQp0b3RhbCA9IG1lZGlhbihzYW1wbGVfc3VtcyhQU0IpKQ0KUFNCLlIgPSB0cmFuc2Zvcm1fc2FtcGxlX2NvdW50cyhQU0IsIHN0YW5kZikNCg0KaW1wb3J0Lm90dS50YWJsZSA8LSBhcy5kYXRhLmZyYW1lKG90dV90YWJsZShQU0IuUikpICU+JQ0KICAjZHBseXI6OnNlbGVjdCgtdGF4b25vbXkpICU+JQ0KICBtdXRhdGVfYWxsKGFzLm51bWVyaWMpICNDb252ZXJ0IHRvIG51bWVyaWMgd2hlcmUgcG9zc2libGUNCg0KY3VyZS5kYXRhID0gUFNCQHNhbV9kYXRhICU+JSBhcy5tYXRyaXgoKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQoNCiNpbXBvcnQudGF4b25vbXkgPSByZWFkLnRhYmxlKCd2aXJvbWVfdGF4b25vbXlfTENBX2tub3duLnR4dCcsIGhlYWRlciA9IFQpDQoNCnJvd25hbWVzIDwtIHJvd25hbWVzKGN1cmUuZGF0YSkNCg0KI1JlbW92ZSBOQSBjb2xvbW5zDQoNCmN1cmUuZGF0YSA8LSBjdXJlLmRhdGFbICwgISBhcHBseSggY3VyZS5kYXRhICwgMiAsIGZ1bmN0aW9uKHgpIGFsbChpcy5uYSh4KSkgKSBdDQoNCiNTZXQgbnVtZXJpYyBjb2x1bW4gY2xhc3MNCmN1cmUuZGF0YSA8LSBjdXJlLmRhdGEgJT4lIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsYXMuZmFjdG9yKQ0KI0FkZCBiYWNrIHJvd25hbWVzDQoNCnJvd25hbWVzKGN1cmUuZGF0YSkgPC0gcm93bmFtZXMNCg0KI2N1cmUuZGF0YSA8LSBjdXJlLmRhdGEgJT4lIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGFzLm51bWVyaWMpDQoNClg4Lm5vbnJhcmVmaWVkID0gdChpbXBvcnQub3R1LnRhYmxlKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIyUlJSBub24tcmFyZWZpZWQNCg0KDQojIyNyYXJlZnlpbmd8c3Vic2FtcGxpbmcgcmVhZHMgaW4gZXZlcnkgc2FtcGxlDQpiYXJwbG90KGNvbFN1bXMoaW1wb3J0Lm90dS50YWJsZSkpDQptaW4oY29sU3VtcyhpbXBvcnQub3R1LnRhYmxlKSkNCg0KcmFyZTggPSBycmFyZWZ5KHQoaW1wb3J0Lm90dS50YWJsZSksIHNhbXBsZSA9IDMwMDAwKQ0KWDgucmFyZWZpZWQgPSBhcy5kYXRhLmZyYW1lKHJhcmU4KSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMjJSUlIHJhcmVmaWVkDQoNCiMjI1N1YnNldCBtZXRhZGF0YSB0byBtYXRjaCByZW1haW5pbmcgc2FtcGxlcyBhZnRlciByYXJlZmFjdGlvbg0KDQpZLmFsbCA9IGN1cmUuZGF0YVtjb2xuYW1lcyhYOC5yYXJlZmllZCksXQ0KDQojIyNMb2cgdHJhbmZvcm1hdGlvbg0KWC5hbGwgPSBsb2cxMChYOC5yYXJlZmllZCsxKQ0KDQojU2VsZWN0IHJlbGV2YW50IG51bWVyaWMgY29sdW1uDQoNCg0KWSA8LSBZLmFsbCAlPiUNCiAgc2VsZWN0KGtleS52YXJzKSAlPiUNCiAgZHJvcF9uYSgpICU+JQ0Kc2VsZWN0X2lmKH4gIWFueShpcy5uYSguKSkpDQoNCiNZIDwtIFlbMTo4XQ0KDQpjb2xuYW1lcyhZKSAjQ2hlY2sgcmVtYWluaW5nIGNvbHVtbnMNCg0KIyMjU2VsZWN0IG9ubHkgbnVtZXJpYyBtZXRhZGF0YSBjdWx1bW5zDQoNClkgIDwtIFkgJT4lIG11dGF0ZV9hbGwoYXMubnVtZXJpYykNCg0KY29sbmFtZXMoWSkgI0NoZWNrIHJlbWFpbmluZyBjb2x1bW5zDQoNCiMjdmlmY29yDQojY29sbGluZWFyaXR5IDwtIHZpZmNvcihZLCB0aCAgPTAuNSkgI2F0IDAuNSB0aHJlc2hvbGQgdmFyaWFibGVzIGhhdmUgYSBWSUYgYmVsb3cgMTAuMDAgKDwwLjIxIGNvcnJlbGF0aW9uISkNCiNjb2xsaW5lYXJpdHkNCg0KI1NlbGVjdCByZWxldmFudCBjb2x1bW5zIGZvciB0aGF0IGFyZSBub24tY29sbGluZWFyDQoNClkuYWQgPSBZDQojWS5hZCA8LSBkcGx5cjo6c2VsZWN0KFkuYWxsLGMoIkJhdGNoIiwgIlRpbWUiKQ0KDQojWS5hZCA8LSBZLmFsbFs4OjIzXQ0KDQojUmVtb3ZlIE5BIHJvd3MNCg0KWSA8LSBZICU+JSBkcm9wX25hKCkNClggPC0gWC5hbGxbLHJvd25hbWVzKFkpXQ0KDQojaXMubmEoWSkNCg0KWCA9IFhbcm93U3VtcyhYW10pPjAsXSANCg0KWCA9IHQoWCkNCmBgYA0KDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IEYsIGVjaG8gPSBGLCBtZXNzYWdlID0gRiwgd2FybmluZz1GfQ0KIyMjIyMjIyMjIyMjIyMjQW5vdmEgb24gY2Fwc2NhbGUgLSBhbGwgdmFyaWFibGVzDQoNCmFub3ZhLm0gPC0gbWF0cml4KG5yb3cgPSAwLCBuY29sID02KSAjQ3JlYXRlIG1hdHJpeCBmb3IgcmVzdWx0cw0KY29sbmFtZXMoYW5vdmEubSkgPC0gYygiRGYiLCJTdW1PZlNxcyIsIkYiLCJQci5GIiwiUmVzaWR1YWwuRGYiLCJSZXNpZHVhbC5TdW1PZlNxcyIpICAgICAgICAgICAgICAgIA0KZm9yIChpIGluIGNvbG5hbWVzKFkpKXsNCiAgYW5vdmEgPC0gYXMubWF0cml4KGFub3ZhLmNjYShjYXBzY2FsZShYIH4gWVssaV0sIGRpc3QgPSAiYnJheSIpLHBlcm11dGF0aW9ucyA9IGhvdyhucGVybT05OTk5OSkpKQ0KICBhbm92YSA8LSBjKGFub3ZhWzEsXSxhbm92YVsyLDE6Ml0pDQogIGFub3ZhLm0gPC1yYmluZChhbm92YS5tLGFub3ZhKQ0KfQ0Kcm93bmFtZXMoYW5vdmEubSkgPC0gY29sbmFtZXMoWSkNCg0KI1ByZXBhcmUgZm9yIHBsb3R0aW5nDQphbm92YS5kYXQgPC0gYW5vdmEubSAlPiUNCiAgYXMuZGF0YS5mcmFtZSAlPiUNCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oIlZhcmlhYmxlIikgJT4lDQogIGFycmFuZ2UoRikNCg0KI0FkZCBhZGp1c3RlZCBwLXZhbHVlcw0KYW5vdmEuZGF0JFByLkYuYWRqIDwtIHAuYWRqdXN0KGFub3ZhLmRhdCRQci5GLCBtZXRob2QgPSAnaG9sbScsIG4gPSBuY29sIChZLmFkKSkNCg0KI2tuaXRyOjprYWJsZShhbm92YS5kYXQpDQoNCiNDYWxjdWxhdGUgc3VtIG9mIHNxdWFyZXMNCmFub3ZhLmRhdCRSMiA8LSBhbm92YS5kYXQkU3VtT2ZTcXMgLyAoYW5vdmEuZGF0JFN1bU9mU3FzICsgYW5vdmEuZGF0JFJlc2lkdWFsLlN1bU9mU3FzKQ0KDQojI0ZhbmN5IHBsb3QNCg0KYW5vdmEubWVsdCA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKGFub3ZhLmRhdCxjb2xzPWMoIlIyIiksIG5hbWVzX3RvPSdtZWFzdXJlJywgdmFsdWVzX3RvPSJ2YWx1ZSIpICU+JQ0KICBhZGRfc2lnbmlmaWNhbmNlKHAuY29sID0gIlByLkYuYWRqIiwgb3V0cHV0LmNvbCA9ICJQckYuc3ltIiwNCiAgICAgICAgICAgICAgICAgICBjdXRwb2ludHMgPSBjKDAsIDFlLTA0LCAwLjAwMSwgMC4wMSwgMC4wNSwgMC4xLDEpLA0KICAgICAgICAgICAgICAgICAgIHN5bWJvbHMgPSBjKCIqKioqIiwgIioqKiIsICIqKiIsICIqIiwgIi4iLCAiIikNCiAgICAgICAgICAgICAgICAgICApDQoNCmFub3ZhLm1lbHQuYmFjIDwtIGFub3ZhLm1lbHQNCg0KZmFuY3kuYW5vdmEuYmFyIDwtIGdnYmFycGxvdChhbm92YS5tZWx0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PSJWYXJpYWJsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9InZhbHVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2NvbG9yID0gIlZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JpZW50YXRpb24gPSBjKCJob3Jpem9udGFsIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gTkEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAibWVhc3VyZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuNyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gYW5vdmEubWVsdCRQckYuc3ltLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIuc2l6ZSA9IDksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi52anVzdCA9IDAuNywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLmhqdXN0ID0gLTAuMw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCikgKw0KICAjc3RhdF9wdmFsdWVfbWFudWFsKA0KICAjICBhZG9uaXMubWVsdCwgIGxhYmVsID0gIlByRi5zeW0iLCB0aXAubGVuZ3RoID0gMC4wMQ0KICAjKSArDQogICNnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjA1KSArDQogIGdndGl0bGUoIlBlcm1hbm92YTogaW5kaXZpZHVhbCBlZmZlY3Qgc2l6ZXMiKSArDQogIHlsYWIoZXhwcmVzc2lvbihSXjJ+InZhbHVlIikpICsNCiAgc2NhbGVfZmlsbF9qY28oKSArDQogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAuMSwxLDAuMSwwLjEsICJjbSIpKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgLjE1KSkpIA0KDQojZmFuY3kuYW5vdmEuYmFyDQoNCmBgYA0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBGLCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQojI0FsbCB2YXJpYWJsZXMNCg0KYWRvbmlzIDwtIGFkb25pczIoWCB+IC4sIGRhdGEgPSBZLCBtZXRob2QgPSAiYnJheSIsIHBlcm11dGF0aW9ucyA9IDk5OTkpICNBbGwgdmFyaWFibGVzDQoNCiNBZGQgYWRqdXN0ZWQgcC12YWx1ZXMNCmFkb25pcyRgUHIoPkYpLmFkamAgPC0gcC5hZGp1c3QoYWRvbmlzJGBQcig+RilgLCBtZXRob2QgPSAnaG9sbScsIG4gPSBuY29sIChZLmFkKSkNCg0KI2tuaXRyOjprYWJsZShhZG9uaXMkYW92LnRhYikNCg0KI1Bsb3R0aW5nIG9yZGVyZWQgUjINCmFkb25pcy5kYXQgPC0gYXMuZGF0YS5mcmFtZShhZG9uaXMpICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiVmFyaWFibGUiKSAgJT4lDQogIGZpbHRlcighVmFyaWFibGUgJWluJSBjKCJSZXNpZHVhbCIsIlRvdGFsIikpICU+JQ0KICBhcnJhbmdlKFIyKQ0KDQphZG9uaXMubWVsdCA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKGFkb25pcy5kYXQsY29scz1jKCJSMiIpLCBuYW1lc190bz0nbWVhc3VyZScsIHZhbHVlc190bz0idmFsdWUiKSAlPiUNCiAgYWRkX3NpZ25pZmljYW5jZShwLmNvbCA9ICJQcig+RikuYWRqIiwNCiAgICAgICAgICAgICAgICAgICBvdXRwdXQuY29sID0gIlByRi5zeW0iLA0KICAgICAgICAgICAgICAgICAgIGN1dHBvaW50cyA9IGMoMCwgMWUtMDQsIDAuMDAxLCAwLjAxLCAwLjA1LCAwLjEsMSksDQogICAgICAgICAgICAgICAgICAgc3ltYm9scyA9IGMoIioqKioiLCAiKioqIiwgIioqIiwgIioiLCAiLiIsICIiKQ0KICAgICAgICAgICAgICAgICAgICkNCg0KDQoNCmZhbmN5LmFkb25pcy5iYXIgPC0gZ2diYXJwbG90KGFkb25pcy5tZWx0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9IlZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT0idmFsdWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjY29sb3IgPSAiVmFyaWFibGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmllbnRhdGlvbiA9IGMoImhvcml6b250YWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJtZWFzdXJlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoMC43KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBhZG9uaXMubWVsdCRQckYuc3ltLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIuc2l6ZSA9IDksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi52anVzdCA9IDAuNywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLmhqdXN0ID0gLTAuMw0KKSArDQogIGdndGl0bGUoIkFkb25pczI6IGRlY29tcG9zaXRpb24gb2YgZWZmZWN0IHNpemVzIikgKw0KICBzY2FsZV9maWxsX2pjbygpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAuMTUpKSkgDQogICNzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGV4cGFuc2lvbihhZGQgPSAuMSkpDQogIA0KDQojZmFuY3kuYWRvbmlzLmJhcg0KDQpgYGANCg0KIyMgRGVwZW5kZW50IGFuZCBpbmRlcGVuZGVudCBlZmZlY3Qgc2l6ZQ0KDQpDYXBzY2FsZSBleGFtaW5lcyB0aGUgY29ycmVsYXRpb24gb2YgZWFjaCB2YXJpYmxlIGluZGVwZW5kZW50bHkuIEFkb25pcyB1c2VzIGRiUkRBIHRvIHF1YW50aWR5IHRoZSBlZmZlY3Qgb2YgdGhlIG1vc3Qgc3Ryb25nZXN0IGNvcnJlbGF0aW5nIGZhY3RvciwgcmVtb3ZpbmcgaXQgYW5kIHRoZW4gZXhhbWluaW5nIHRoZSByZW1haW5pbmcgZWZmZWN0IG9mIHRoZSBuZXh0IGZhY3RvciBhbmQgc28gZm9ydGguLi4NCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGLCAsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xNSwgZmlnLmZ1bGx3aWR0aCA9IFRSVUV9DQpjb3dwbG90OjpwbG90X2dyaWQoZmFuY3kuYW5vdmEuYmFyLCBmYW5jeS5hZG9uaXMuYmFyKSAgKw0KICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKQ0KYGBgDQoNCmBgYHtyLCBldmFsID0gRiwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRiwgLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTUsIGZpZy5mdWxsd2lkdGggPSBUUlVFfQ0KZ2dzYXZlKCJFZmZlY3Rfc2l6ZV9hbGxfdmFyaWFibGVzLnRpZmYiLHdpZHRoID0gMjUsIGhlaWdodCA9IDUwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDI1MCkgDQpgYGANCg0KIyMgQWRqdXN0ZWQgZm9yIHRpbWVwb2ludA0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEYsIHdhcm5pbmc9Rn0NCiMjIyMjIyMjIyMjIyMjI0Fub3ZhIG9uIGNhcHNjYWxlIC0gYWxsIHZhcmlhYmxlcw0KDQphbm92YS5tIDwtIG1hdHJpeChucm93ID0gMCwgbmNvbCA9NikgI0NyZWF0ZSBtYXRyaXggZm9yIHJlc3VsdHMNCmNvbG5hbWVzKGFub3ZhLm0pIDwtIGMoIkRmIiwiU3VtT2ZTcXMiLCJGIiwiUHIuRiIsIlJlc2lkdWFsLkRmIiwiUmVzaWR1YWwuU3VtT2ZTcXMiKSAgICAgICAgICAgICAgICANCmZvciAoaSBpbiBjb2xuYW1lcyhkcGx5cjo6c2VsZWN0KFksLWMoIlRpbWVwb2ludCIpKSkpew0KICBhbm92YSA8LSBhcy5tYXRyaXgoYW5vdmEuY2NhKGNhcHNjYWxlKFggfiBZWyxpXSArIFRpbWVwb2ludCwgWSwgZGlzdCA9ICJicmF5IikscGVybXV0YXRpb25zID0gaG93KG5wZXJtPTk5OTkpKSkNCiAgYW5vdmEgPC0gYyhhbm92YVsxLF0sYW5vdmFbMiwxOjJdKQ0KICBhbm92YS5tIDwtcmJpbmQoYW5vdmEubSxhbm92YSkNCn0NCnJvd25hbWVzKGFub3ZhLm0pIDwtIGNvbG5hbWVzKGRwbHlyOjpzZWxlY3QoWSwtYygiVGltZXBvaW50IikpKQ0KDQojUHJlcGFyZSBmb3IgcGxvdHRpbmcNCmFub3ZhLmRhdCA8LSBhbm92YS5tICU+JQ0KICBhcy5kYXRhLmZyYW1lICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiVmFyaWFibGUiKSAlPiUNCiAgYXJyYW5nZShGKQ0KDQojQWRkIGFkanVzdGVkIHAtdmFsdWVzDQphbm92YS5kYXQkUHIuRi5hZGogPC0gcC5hZGp1c3QoYW5vdmEuZGF0JFByLkYsIG1ldGhvZCA9ICdob2xtJywgbiA9IG5jb2wgKFkuYWQpKQ0KDQoja25pdHI6OmthYmxlKGFub3ZhLmRhdCkNCg0KI0NhbGN1bGF0ZSBzdW0gb2Ygc3F1YXJlcw0KYW5vdmEuZGF0JFIyIDwtIGFub3ZhLmRhdCRTdW1PZlNxcyAvIChhbm92YS5kYXQkU3VtT2ZTcXMgKyBhbm92YS5kYXQkUmVzaWR1YWwuU3VtT2ZTcXMpDQoNCiNGaXggbmFtZXMNCmFub3ZhLmRhdCRWYXJpYWJsZSA8LSBnc3ViKCJfIiwiICIsYW5vdmEuZGF0JFZhcmlhYmxlKQ0KDQojI0ZhbmN5IHBsb3QNCg0KYW5vdmEubWVsdCA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKGFub3ZhLmRhdCxjb2xzPWMoIlIyIiksIG5hbWVzX3RvPSdtZWFzdXJlJywgdmFsdWVzX3RvPSJ2YWx1ZSIpICU+JQ0KICBhZGRfc2lnbmlmaWNhbmNlKHAuY29sID0gIlByLkYuYWRqIiwgb3V0cHV0LmNvbCA9ICJQckYuc3ltIiwNCiAgICAgICAgICAgICAgICAgICBjdXRwb2ludHMgPSBjKDAsIDFlLTA0LCAwLjAwMSwgMC4wMSwgMC4wNSwgMC4xLDEpLA0KICAgICAgICAgICAgICAgICAgIHN5bWJvbHMgPSBjKCIqKioqIiwgIioqKiIsICIqKiIsICIqIiwgIi4iLCAiIikNCiAgICAgICAgICAgICAgICAgICApDQoNCnBlcm1hbm92YS5jdGltZS5tb3RoZXIgPC0gYW5vdmEubWVsdA0KDQpmYW5jeS5hbm92YS5iYXIubW90aGVyIDwtIGdnYmFycGxvdChhbm92YS5tZWx0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PSJWYXJpYWJsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9InZhbHVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2NvbG9yID0gIlZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JpZW50YXRpb24gPSBjKCJob3Jpem9udGFsIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gTkEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAibWVhc3VyZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuNyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gYW5vdmEubWVsdCRQckYuc3ltLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIuc2l6ZSA9IDksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi52anVzdCA9IDAuNywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLmhqdXN0ID0gLTAuMw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCikgKw0KICAjc3RhdF9wdmFsdWVfbWFudWFsKA0KICAjICBhZG9uaXMubWVsdCwgIGxhYmVsID0gIlByRi5zeW0iLCB0aXAubGVuZ3RoID0gMC4wMQ0KICAjKSArDQogICNnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjA1KSArDQogICNnZ3RpdGxlKCJQZXJtYW5vdmE6IGluZGl2aWR1YWwgZWZmZWN0IHNpemVzIikgKw0KICB4bGFiKCIiKSArDQogIHlsYWIoZXhwcmVzc2lvbihSXjJ+InZhbHVlIikpICsNCiAgc2NhbGVfZmlsbF9qY28oKSArDQogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKDAuMSwxLDAuMSwwLjEsICJjbSIpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAuMikpLGJyZWFrcyA9IGMoMC4wMCwgMC4wMSwgMC4wMikpIA0KDQpmYW5jeS5hbm92YS5iYXIubW90aGVyDQoNCmBgYA0KDQojIyMgQWRqdXN0ZWQgZm9yIGluZmFudCBzZXggKyB0aW1lcG9pbnQNCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nPUZ9DQojIyMjIyMjIyMjIyMjIyNBbm92YSBvbiBjYXBzY2FsZSAtIGFsbCB2YXJpYWJsZXMNCg0KYW5vdmEubSA8LSBtYXRyaXgobnJvdyA9IDAsIG5jb2wgPTYpICNDcmVhdGUgbWF0cml4IGZvciByZXN1bHRzDQpjb2xuYW1lcyhhbm92YS5tKSA8LSBjKCJEZiIsIlN1bU9mU3FzIiwiRiIsIlByLkYiLCJSZXNpZHVhbC5EZiIsIlJlc2lkdWFsLlN1bU9mU3FzIikgICAgICAgICAgICAgICAgDQpmb3IgKGkgaW4gY29sbmFtZXMoZHBseXI6OnNlbGVjdChZLC1jKCJUaW1lcG9pbnQiLCJTZXhfY2hpbGQiKSkpKXsNCiAgYW5vdmEgPC0gYXMubWF0cml4KGFub3ZhLmNjYShjYXBzY2FsZShYIH4gWVssaV0gKyBUaW1lcG9pbnQgKyBDb25kaXRpb24oU2V4X2NoaWxkKSwgWSwgZGlzdCA9ICJicmF5IikscGVybXV0YXRpb25zID0gaG93KG5wZXJtPTk5OTkpKSkNCiAgYW5vdmEgPC0gYyhhbm92YVsxLF0sYW5vdmFbMiwxOjJdKQ0KICBhbm92YS5tIDwtcmJpbmQoYW5vdmEubSxhbm92YSkNCn0NCnJvd25hbWVzKGFub3ZhLm0pIDwtIGNvbG5hbWVzKGRwbHlyOjpzZWxlY3QoWSwtYygiVGltZXBvaW50IiwiU2V4X2NoaWxkIikpKQ0KDQojUHJlcGFyZSBmb3IgcGxvdHRpbmcNCmFub3ZhLmRhdCA8LSBhbm92YS5tICU+JQ0KICBhcy5kYXRhLmZyYW1lICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiVmFyaWFibGUiKSAlPiUNCiAgYXJyYW5nZShGKQ0KDQojQWRkIGFkanVzdGVkIHAtdmFsdWVzDQphbm92YS5kYXQkUHIuRi5hZGogPC0gcC5hZGp1c3QoYW5vdmEuZGF0JFByLkYsIG1ldGhvZCA9ICdob2xtJywgbiA9IG5jb2wgKFkuYWQpKQ0KDQoja25pdHI6OmthYmxlKGFub3ZhLmRhdCkNCg0KI0NhbGN1bGF0ZSBzdW0gb2Ygc3F1YXJlcw0KYW5vdmEuZGF0JFIyIDwtIGFub3ZhLmRhdCRTdW1PZlNxcyAvIChhbm92YS5kYXQkU3VtT2ZTcXMgKyBhbm92YS5kYXQkUmVzaWR1YWwuU3VtT2ZTcXMpDQoNCiNGaXggbmFtZXMNCmFub3ZhLmRhdCRWYXJpYWJsZSA8LSBnc3ViKCJfIiwiICIsYW5vdmEuZGF0JFZhcmlhYmxlKQ0KDQojI0ZhbmN5IHBsb3QNCg0KYW5vdmEubWVsdCA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKGFub3ZhLmRhdCxjb2xzPWMoIlIyIiksIG5hbWVzX3RvPSdtZWFzdXJlJywgdmFsdWVzX3RvPSJ2YWx1ZSIpICU+JQ0KICBhZGRfc2lnbmlmaWNhbmNlKHAuY29sID0gIlByLkYuYWRqIiwgb3V0cHV0LmNvbCA9ICJQckYuc3ltIiwNCiAgICAgICAgICAgICAgICAgICBjdXRwb2ludHMgPSBjKDAsIDFlLTA0LCAwLjAwMSwgMC4wMSwgMC4wNSwgMC4xLDEpLA0KICAgICAgICAgICAgICAgICAgIHN5bWJvbHMgPSBjKCIqKioqIiwgIioqKiIsICIqKiIsICIqIiwgIi4iLCAiIikNCiAgICAgICAgICAgICAgICAgICApDQoNCnBlcm1hbm92YS5jdGltZS5tb3RoZXIuc2V4IDwtIGFub3ZhLm1lbHQNCg0KZmFuY3kuYW5vdmEuYmFyLm1vdGhlci5zZXggPC0gZ2diYXJwbG90KGFub3ZhLm1lbHQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9IlZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT0idmFsdWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjY29sb3IgPSAiVmFyaWFibGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmllbnRhdGlvbiA9IGMoImhvcml6b250YWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJtZWFzdXJlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoMC43KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBhbm92YS5tZWx0JFByRi5zeW0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi5zaXplID0gOSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLnZqdXN0ID0gMC43LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIuaGp1c3QgPSAtMC4zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KKSArDQogICNzdGF0X3B2YWx1ZV9tYW51YWwoDQogICMgIGFkb25pcy5tZWx0LCAgbGFiZWwgPSAiUHJGLnN5bSIsIHRpcC5sZW5ndGggPSAwLjAxDQogICMpICsNCiAgI2dlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMDUpICsNCiAgI2dndGl0bGUoIlBlcm1hbm92YTogaW5kaXZpZHVhbCBlZmZlY3Qgc2l6ZXMiKSArDQogIHhsYWIoIiIpICsNCiAgeWxhYihleHByZXNzaW9uKFJeMn4idmFsdWUiKSkgKw0KICBzY2FsZV9maWxsX2pjbygpICsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMC4xLDEsMC4xLDAuMSwgImNtIiksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIC4xNSkpKSANCg0KZmFuY3kuYW5vdmEuYmFyLm1vdGhlci5zZXgNCg0KYGBgDQoNCiMjIEluZmFudCBmYWN0b3JzDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRiwgd2FybmluZz1GfQ0KWSA8LSBZLmFsbCAlPiUNCiAgc2VsZWN0KGtleS52YXJzLmluZikgJT4lDQogIGRyb3BfbmEoKSAlPiUNCnNlbGVjdF9pZih+ICFhbnkoaXMubmEoLikpKQ0KDQojWSA8LSBZWzE6OF0NCg0KY29sbmFtZXMoWSkgI0NoZWNrIHJlbWFpbmluZyBjb2x1bW5zDQoNCiMjI1NlbGVjdCBvbmx5IG51bWVyaWMgbWV0YWRhdGEgY3VsdW1ucw0KDQpZICA8LSBZICU+JSBtdXRhdGVfYWxsKGFzLm51bWVyaWMpDQoNCmNvbG5hbWVzKFkpICNDaGVjayByZW1haW5pbmcgY29sdW1ucw0KDQojI3ZpZmNvcg0KI2NvbGxpbmVhcml0eSA8LSB2aWZjb3IoWSwgdGggID0wLjUpICNhdCAwLjUgdGhyZXNob2xkIHZhcmlhYmxlcyBoYXZlIGEgVklGIGJlbG93IDEwLjAwICg8MC4yMSBjb3JyZWxhdGlvbiEpDQojY29sbGluZWFyaXR5DQoNCiNTZWxlY3QgcmVsZXZhbnQgY29sdW1ucyBmb3IgdGhhdCBhcmUgbm9uLWNvbGxpbmVhcg0KDQpZLmFkID0gWQ0KI1kuYWQgPC0gZHBseXI6OnNlbGVjdChZLmFsbCxjKCJCYXRjaCIsICJUaW1lIikNCg0KI1kuYWQgPC0gWS5hbGxbODoyM10NCg0KI1JlbW92ZSBOQSByb3dzDQoNClkgPC0gWSAlPiUgZHJvcF9uYSgpDQpYIDwtIFguYWxsWyxyb3duYW1lcyhZKV0NCg0KWCA9IFhbcm93U3VtcyhYW10pPjAsXSANCg0KWCA9IHQoWCkNCmBgYA0KDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRiwgd2FybmluZz1GfQ0KIyMjIyMjIyMjIyMjIyMjQW5vdmEgb24gY2Fwc2NhbGUgLSBhbGwgdmFyaWFibGVzDQoNCmFub3ZhLm0gPC0gbWF0cml4KG5yb3cgPSAwLCBuY29sID02KSAjQ3JlYXRlIG1hdHJpeCBmb3IgcmVzdWx0cw0KY29sbmFtZXMoYW5vdmEubSkgPC0gYygiRGYiLCJTdW1PZlNxcyIsIkYiLCJQci5GIiwiUmVzaWR1YWwuRGYiLCJSZXNpZHVhbC5TdW1PZlNxcyIpICAgICAgICAgICAgICAgIA0KZm9yIChpIGluIGNvbG5hbWVzKGRwbHlyOjpzZWxlY3QoWSwtYygiVGltZXBvaW50IikpKSl7DQogIGFub3ZhIDwtIGFzLm1hdHJpeChhbm92YS5jY2EoY2Fwc2NhbGUoWCB+IFlbLGldICsgVGltZXBvaW50LCBZLCBkaXN0ID0gImJyYXkiKSxwZXJtdXRhdGlvbnMgPSBob3cobnBlcm09OTk5OTkpKSkNCiAgYW5vdmEgPC0gYyhhbm92YVsxLF0sYW5vdmFbMiwxOjJdKQ0KICBhbm92YS5tIDwtcmJpbmQoYW5vdmEubSxhbm92YSkNCn0NCnJvd25hbWVzKGFub3ZhLm0pIDwtIGNvbG5hbWVzKGRwbHlyOjpzZWxlY3QoWSwtYygiVGltZXBvaW50IikpKQ0KDQojUHJlcGFyZSBmb3IgcGxvdHRpbmcNCmFub3ZhLmRhdCA8LSBhbm92YS5tICU+JQ0KICBhcy5kYXRhLmZyYW1lICU+JQ0KICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiVmFyaWFibGUiKSAlPiUNCiAgYXJyYW5nZShGKQ0KDQojQWRkIGFkanVzdGVkIHAtdmFsdWVzDQphbm92YS5kYXQkUHIuRi5hZGogPC0gcC5hZGp1c3QoYW5vdmEuZGF0JFByLkYsIG1ldGhvZCA9ICdob2xtJywgbiA9IG5jb2wgKFkuYWQpKQ0KDQoja25pdHI6OmthYmxlKGFub3ZhLmRhdCkNCg0KI0NhbGN1bGF0ZSBzdW0gb2Ygc3F1YXJlcw0KYW5vdmEuZGF0JFIyIDwtIGFub3ZhLmRhdCRTdW1PZlNxcyAvIChhbm92YS5kYXQkU3VtT2ZTcXMgKyBhbm92YS5kYXQkUmVzaWR1YWwuU3VtT2ZTcXMpDQoNCiNGaXggbmFtZXMNCmFub3ZhLmRhdCRWYXJpYWJsZSA8LSBnc3ViKCJfIiwiICIsYW5vdmEuZGF0JFZhcmlhYmxlKQ0KDQojI0ZhbmN5IHBsb3QNCg0KYW5vdmEubWVsdCA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKGFub3ZhLmRhdCxjb2xzPWMoIlIyIiksIG5hbWVzX3RvPSdtZWFzdXJlJywgdmFsdWVzX3RvPSJ2YWx1ZSIpICU+JQ0KICBhZGRfc2lnbmlmaWNhbmNlKHAuY29sID0gIlByLkYuYWRqIiwgb3V0cHV0LmNvbCA9ICJQckYuc3ltIiwNCiAgICAgICAgICAgICAgICAgICBjdXRwb2ludHMgPSBjKDAsIDFlLTA0LCAwLjAwMSwgMC4wMSwgMC4wNSwgMC4xLDEpLA0KICAgICAgICAgICAgICAgICAgIHN5bWJvbHMgPSBjKCIqKioqIiwgIioqKiIsICIqKiIsICIqIiwgIi4iLCAiIikNCiAgICAgICAgICAgICAgICAgICApDQoNCnBlcm1hbm92YS5jdGltZS5pbmYgPC0gYW5vdmEubWVsdA0KDQpmYW5jeS5hbm92YS5iYXIuaW5mIDwtIGdnYmFycGxvdChhbm92YS5tZWx0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PSJWYXJpYWJsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9InZhbHVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2NvbG9yID0gIlZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JpZW50YXRpb24gPSBjKCJob3Jpem9udGFsIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gTkEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAibWVhc3VyZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuNyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gYW5vdmEubWVsdCRQckYuc3ltLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIuc2l6ZSA9IDksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi52anVzdCA9IDAuNywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLmhqdXN0ID0gLTAuMw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCikgKw0KICAjc3RhdF9wdmFsdWVfbWFudWFsKA0KICAjICBhZG9uaXMubWVsdCwgIGxhYmVsID0gIlByRi5zeW0iLCB0aXAubGVuZ3RoID0gMC4wMQ0KICAjKSArDQogICNnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjA1KSArDQogIHhsYWIoIiIpICsNCiAgeWxhYihleHByZXNzaW9uKFJeMn4idmFsdWUiKSkgKw0KICBzY2FsZV9maWxsX2pjbygpICsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMC4xLDEsMC4xLDAuMSwgImNtIiksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIC4xNSkpKSANCg0KZmFuY3kuYW5vdmEuYmFyLmluZg0KDQpgYGANCg0KIyMgQ29ydGlzb2wNCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nPUZ9DQpZIDwtIFkuYWxsICU+JQ0KICBzZWxlY3Qoa2V5LnZhcnMuY29ydGlzb2wpICU+JQ0KICBkcm9wX25hKCkgJT4lDQpzZWxlY3RfaWYofiAhYW55KGlzLm5hKC4pKSkNCg0KI1kgPC0gWVsxOjhdDQoNCmNvbG5hbWVzKFkpICNDaGVjayByZW1haW5pbmcgY29sdW1ucw0KDQojIyNTZWxlY3Qgb25seSBudW1lcmljIG1ldGFkYXRhIGN1bHVtbnMNCg0KWSAgPC0gWSAlPiUgbXV0YXRlX2FsbChhcy5udW1lcmljKQ0KDQpjb2xuYW1lcyhZKSAjQ2hlY2sgcmVtYWluaW5nIGNvbHVtbnMNCg0KIyN2aWZjb3INCiNjb2xsaW5lYXJpdHkgPC0gdmlmY29yKFksIHRoICA9MC41KSAjYXQgMC41IHRocmVzaG9sZCB2YXJpYWJsZXMgaGF2ZSBhIFZJRiBiZWxvdyAxMC4wMCAoPDAuMjEgY29ycmVsYXRpb24hKQ0KI2NvbGxpbmVhcml0eQ0KDQojU2VsZWN0IHJlbGV2YW50IGNvbHVtbnMgZm9yIHRoYXQgYXJlIG5vbi1jb2xsaW5lYXINCg0KI1kuYWQgPC0gZHBseXI6OnNlbGVjdChZLmFsbCxjKCJCYXRjaCIsICJUaW1lIikNCg0KI1kuYWQgPC0gWS5hbGxbODoyM10NCg0KI1JlbW92ZSBOQSByb3dzDQoNClkgPC0gWSAlPiUgZHJvcF9uYSgpICU+JSBkcGx5cjo6cmVuYW1lKA0KICAgIGBITSBjb3J0aXNvbCBBVUMgZGF5IDEwYCA9IGBITV9jb3J0aXNvbF9BVUNfMWAsDQogICAgYEhNIGNvcnRpc29sIEFVQyBkYXkgMmAgPSBgSE1fY29ydGlzb2xfQVVDXzJgLA0KICAgIGBTYWxpdmEgY29ydGlzb2wgbW9ybmluZyBwZWFrYCA9IGBTYWxpdmFfY29ydGlzb2xfbW9ybmluZ19wZWFrYA0KICApDQoNCg0KWCA8LSBYLmFsbFsscm93bmFtZXMoWSldDQoNClggPSBYW3Jvd1N1bXMoWFtdKT4wLF0gDQoNClggPSB0KFgpDQpgYGANCg0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEYsIHdhcm5pbmc9Rn0NCiMjIyMjIyMjIyMjIyMjI0Fub3ZhIG9uIGNhcHNjYWxlIC0gYWxsIHZhcmlhYmxlcw0KDQphbm92YS5tIDwtIG1hdHJpeChucm93ID0gMCwgbmNvbCA9NikgI0NyZWF0ZSBtYXRyaXggZm9yIHJlc3VsdHMNCmNvbG5hbWVzKGFub3ZhLm0pIDwtIGMoIkRmIiwiU3VtT2ZTcXMiLCJGIiwiUHIuRiIsIlJlc2lkdWFsLkRmIiwiUmVzaWR1YWwuU3VtT2ZTcXMiKSAgICAgICAgICAgICAgICANCmZvciAoaSBpbiBjb2xuYW1lcyhkcGx5cjo6c2VsZWN0KFksLWMoIlRpbWVwb2ludCIpKSkpew0KICBhbm92YSA8LSBhcy5tYXRyaXgoYW5vdmEuY2NhKGNhcHNjYWxlKFggfiBZWyxpXSArIFRpbWVwb2ludCwgWSwgZGlzdCA9ICJicmF5IikscGVybXV0YXRpb25zID0gaG93KG5wZXJtPTk5OTk5KSkpDQogIGFub3ZhIDwtIGMoYW5vdmFbMSxdLGFub3ZhWzIsMToyXSkNCiAgYW5vdmEubSA8LXJiaW5kKGFub3ZhLm0sYW5vdmEpDQp9DQpyb3duYW1lcyhhbm92YS5tKSA8LSBjb2xuYW1lcyhkcGx5cjo6c2VsZWN0KFksLWMoIlRpbWVwb2ludCIpKSkNCg0KI1ByZXBhcmUgZm9yIHBsb3R0aW5nDQphbm92YS5kYXQgPC0gYW5vdmEubSAlPiUNCiAgYXMuZGF0YS5mcmFtZSAlPiUNCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oIlZhcmlhYmxlIikgJT4lDQogIGFycmFuZ2UoRikNCg0KI0FkZCBhZGp1c3RlZCBwLXZhbHVlcw0KYW5vdmEuZGF0JFByLkYuYWRqIDwtIHAuYWRqdXN0KGFub3ZhLmRhdCRQci5GLCBtZXRob2QgPSAnaG9sbScsIG4gPSBuY29sIChZLmFkKSkNCg0KI2tuaXRyOjprYWJsZShhbm92YS5kYXQpDQoNCiNDYWxjdWxhdGUgc3VtIG9mIHNxdWFyZXMNCmFub3ZhLmRhdCRSMiA8LSBhbm92YS5kYXQkU3VtT2ZTcXMgLyAoYW5vdmEuZGF0JFN1bU9mU3FzICsgYW5vdmEuZGF0JFJlc2lkdWFsLlN1bU9mU3FzKQ0KDQojRml4IG5hbWVzDQphbm92YS5kYXQkVmFyaWFibGUgPC0gZ3N1YigiXyIsIiAiLGFub3ZhLmRhdCRWYXJpYWJsZSkNCg0KIyNGYW5jeSBwbG90DQoNCmFub3ZhLm1lbHQgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihhbm92YS5kYXQsY29scz1jKCJSMiIpLCBuYW1lc190bz0nbWVhc3VyZScsIHZhbHVlc190bz0idmFsdWUiKSAlPiUNCiAgYWRkX3NpZ25pZmljYW5jZShwLmNvbCA9ICJQci5GLmFkaiIsIG91dHB1dC5jb2wgPSAiUHJGLnN5bSIsDQogICAgICAgICAgICAgICAgICAgY3V0cG9pbnRzID0gYygwLCAxZS0wNCwgMC4wMDEsIDAuMDEsIDAuMDUsIDAuMSwxKSwNCiAgICAgICAgICAgICAgICAgICBzeW1ib2xzID0gYygiKioqKiIsICIqKioiLCAiKioiLCAiKiIsICIuIiwgIiIpDQogICAgICAgICAgICAgICAgICAgKQ0KDQphbm92YS5tZWx0DQoNCnBlcm1hbm92YS5jdGltZS5jb3J0IDwtIGFub3ZhLm1lbHQNCg0KZmFuY3kuYW5vdmEuYmFyLmNvcnQgPC0gZ2diYXJwbG90KGFub3ZhLm1lbHQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9IlZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT0idmFsdWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjY29sb3IgPSAiVmFyaWFibGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmllbnRhdGlvbiA9IGMoImhvcml6b250YWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBOQSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJtZWFzdXJlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoMC43KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBhbm92YS5tZWx0JFByRi5zeW0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYi5zaXplID0gOSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiLnZqdXN0ID0gMC43LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWIuaGp1c3QgPSAtMC4zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KKSArDQogICNzdGF0X3B2YWx1ZV9tYW51YWwoDQogICMgIGFkb25pcy5tZWx0LCAgbGFiZWwgPSAiUHJGLnN5bSIsIHRpcC5sZW5ndGggPSAwLjAxDQogICMpICsNCiAgI2dlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMDUpICsNCiAgeGxhYigiIikgKw0KICB5bGFiKGV4cHJlc3Npb24oUl4yfiJ2YWx1ZSIpKSArDQogIHNjYWxlX2ZpbGxfamNvKCkgKw0KICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigwLjEsMSwwLjEsMC4xLCAiY20iKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAuMTUpKSkgDQoNCmZhbmN5LmFub3ZhLmJhci5jb3J0DQoNCmBgYA0KDQojIE1ldGFkYXRhIGF1dG8gY29ycmVsYXRpb25zDQoNCmBgYHtyLCBldmFsID0gRiwgaW5jbHVkZSA9IEYsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCg0KDQptZXRhLnBhaXJzIDwtIG1ldGEgJT4lDQogIHNlbGVjdChjKCJTdHJlc3NfZ3JvdXAiLA0KICAgICAgICAgICAiU2V4X2NoaWxkIiwNCiAgICAgICAgICAgIlBTU19zdHJlc3Nfc2NvcmUiLA0KICAgICAgICAgICAiTFNDcl9zdHJlc3Nfc2NvcmUiLA0KICAgICAgICAgICAiRWR1Y2F0aW9uX21vdGhlciIsDQogICAgICAgICAgICJCTUlfbW90aGVyIiwNCiAgICAgICAgICAgIlRpbWVwb2ludCIsDQogICAgICAgICAgICJIYWlyLmNvcnRpc29sIg0KICAgICAgICAgICApKSAlPiUgDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCByb3VuZCkNCg0KbGlicmFyeShHR2FsbHkpDQoNCmdncGFpcnM8LWdncGFpcnMobWV0YS5wYWlycykNCg0KZ2dzYXZlKCJyZXN1bHRzL21ldGFkYXRhX2F1dG9fY29yX2dnYWxseS5wZGYiLGdncGFpcnMsd2lkdGg9MzAsaGVpZ2h0PTMwLGxpbWl0c2l6ZSA9IEZBTFNFLCB1bml0cyA9ICJjbSIsIGRwaSA9IDQwMCkNCg0KZ2dwYWlycw0KDQpnZ3BhaXJzX3RpbWU8LWdncGFpcnMobWV0YS5wYWlycywNCiAgICAgICAgICAgICAgICAgbWFwcGluZz1nZ3Bsb3QyOjphZXMoY29sb3VyID0gVGltZXBvaW50KSwNCiAgICAgICAgICAgICAgICAgbG93ZXI9bGlzdChjb21ibz13cmFwKCJmYWNldGhpc3QiLGJpbndpZHRoPTEpKQ0KICAgICAgICAgICAgICAgICApDQoNCmdncGFpcnNfdGltZQ0KDQpnZ3NhdmUoInJlc3VsdHMvbWV0YWRhdGFfYXV0b19jb3JfZ2dhbGx5X3RpbWUucGRmIixnZ3BhaXJzX3RpbWUsd2lkdGg9MzAsaGVpZ2h0PTMwLGxpbWl0c2l6ZSA9IEZBTFNFLCB1bml0cyA9ICJjbSIsIGRwaSA9IDQwMCkNCg0KZ2dwYWlyc19zdHJlc3NfZ3JvdXA8LWdncGFpcnMobWV0YS5wYWlycywNCiAgICAgICAgICAgICAgICAgbWFwcGluZz1nZ3Bsb3QyOjphZXMoY29sb3VyID0gU3RyZXNzX2dyb3VwKSwNCiAgICAgICAgICAgICAgICAgbG93ZXI9bGlzdChjb21ibz13cmFwKCJmYWNldGhpc3QiLGJpbndpZHRoPTEpKQ0KICAgICAgICAgICAgICAgICApDQoNCmdncGFpcnNfc3RyZXNzX2dyb3VwDQoNCmdnc2F2ZSgicmVzdWx0cy9tZXRhZGF0YV9hdXRvX2Nvcl9nZ2FsbHlfc3RyZXNzX2dyb3VwLnBkZiIsZ2dwYWlyc19zdHJlc3NfZ3JvdXAsd2lkdGg9MzAsaGVpZ2h0PTMwLGxpbWl0c2l6ZSA9IEZBTFNFLCB1bml0cyA9ICJjbSIsIGRwaSA9IDQwMCkNCg0KDQoNCmBgYA0KDQojIE1pY3JvZWNvIHBsb3RzDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCm1lY29fZGF0IDwtIGZpbGUybWVjbzo6cGh5bG9zZXEybWVjbyhQU0IpDQpgYGANCg0KIyBCZXRhIGRpdmVyc2l0eQ0KDQojIyBUaW1lDQoNCmBgYHtyfQ0KdmFyaWFibGUgPSAiU3RyZXNzX2dyb3VwIg0KDQoNCiNDYWxjdWx0YSBiZXRhIGRpdmVyc2l0eSBtZXRyaWNzDQptZWNvX2RhdCRjYWxfYmV0YWRpdih1bmlmcmFjID0gVFJVRSkNCg0KIyBjcmVhdGUgYW4gdHJhbnNfYmV0YSBvYmplY3QNCiMgbWVhc3VyZSBwYXJhbWV0ZXIgbXVzdCBiZSBvbmUgb2YgbmFtZXMoZGF0YXNldCRiZXRhX2RpdmVyc2l0eSkNCnQxIDwtIHRyYW5zX2JldGEkbmV3KGRhdGFzZXQgPSBtZWNvX2RhdCwgZ3JvdXAgPSB2YXJpYWJsZSwgbWVhc3VyZSA9ICJicmF5IikNCg0KI1BDb0EsIFBDQSBhbmQgTk1EUyBhcmUgYXZhaWxhYmxlDQp0MSRjYWxfb3JkaW5hdGlvbihvcmRpbmF0aW9uID0gIlBDb0EiKQ0KDQojIHQxJHJlc19vcmRpbmF0aW9uIGlzIHRoZSBvcmRpbmF0aW9uIHJlc3VsdCBsaXN0DQojY2xhc3ModDEkcmVzX29yZGluYXRpb24pDQoNCiMgcGxvdCB0aGUgUENvQSByZXN1bHQgd2l0aCBjb25maWRlbmNlIGVsbGlwc2UNCiN0MSRwbG90X29yZGluYXRpb24ocGxvdF9jb2xvciA9IHZhcmlhYmxlLCBwbG90X3NoYXBlID0gdmFyaWFibGUsIHBsb3RfdHlwZSA9IGMoInBvaW50IiwgImVsbGlwc2UiKSkNCmBgYA0KDQojIyMgV2l0aGluLWdyb3VwIGRpc3RhbmNlcw0KDQpgYGB7cn0NCiMgY2FsY3VsYXRlIGFuZCBwbG90IHNhbXBsZSBkaXN0YW5jZXMgd2l0aGluIGdyb3Vwcw0KdDEkY2FsX2dyb3VwX2Rpc3RhbmNlKHdpdGhpbl9ncm91cCA9IFRSVUUpDQojIHJldHVybiB0MSRyZXNfZ3JvdXBfZGlzdGFuY2UNCiMgcGVyZm9ybSBXaWxjb3hvbiBSYW5rIFN1bSBhbmQgU2lnbmVkIFJhbmsgVGVzdHMNCnQxJGNhbF9ncm91cF9kaXN0YW5jZV9kaWZmKG1ldGhvZCA9ICJ3aWxjb3giKQ0KIyBwbG90X2dyb3VwX29yZGVyIHBhcmFtZXRlciBjYW4gYmUgdXNlZCB0byBhZGp1c3Qgb3JkZXJzIGluIHggYXhpcw0KdDEkcGxvdF9ncm91cF9kaXN0YW5jZShib3hwbG90X2FkZCA9ICJtZWFuIikNCmBgYA0KDQojIyMjIERpc3BlcnNpb24NCg0KYGBge3J9DQojIGZvciB0aGUgd2hvbGUgY29tcGFyaXNvbiBhbmQgZm9yIGVhY2ggcGFpcmVkIGdyb3Vwcw0KdDEkY2FsX2JldGFkaXNwZXIoKQ0KIyMgVGhlIHJlc3VsdCBpcyBzdG9yZWQgaW4gb2JqZWN0JHJlc19iZXRhZGlzcGVyIC4uLg0KdDEkcmVzX2JldGFkaXNwZXINCmBgYA0KDQojIyBUaW1lcG9pbnQNCg0KYGBge3J9DQp2YXJpYWJsZSA9ICJUaW1lcG9pbnQiDQojIGNyZWF0ZSBhbiB0cmFuc19iZXRhIG9iamVjdA0KIyBtZWFzdXJlIHBhcmFtZXRlciBtdXN0IGJlIG9uZSBvZiBuYW1lcyhkYXRhc2V0JGJldGFfZGl2ZXJzaXR5KQ0KdDEgPC0gdHJhbnNfYmV0YSRuZXcoZGF0YXNldCA9IG1lY29fZGF0LCBncm91cCA9IHZhcmlhYmxlLCBtZWFzdXJlID0gImJyYXkiKQ0KDQojUENvQSwgUENBIGFuZCBOTURTIGFyZSBhdmFpbGFibGUNCnQxJGNhbF9vcmRpbmF0aW9uKG9yZGluYXRpb24gPSAiUENvQSIpDQoNCiMgdDEkcmVzX29yZGluYXRpb24gaXMgdGhlIG9yZGluYXRpb24gcmVzdWx0IGxpc3QNCiNjbGFzcyh0MSRyZXNfb3JkaW5hdGlvbikNCg0KIyBwbG90IHRoZSBQQ29BIHJlc3VsdCB3aXRoIGNvbmZpZGVuY2UgZWxsaXBzZQ0KI3QxJHBsb3Rfb3JkaW5hdGlvbihwbG90X2NvbG9yID0gdmFyaWFibGUsIHBsb3Rfc2hhcGUgPSB2YXJpYWJsZSwgcGxvdF90eXBlID0gYygicG9pbnQiLCAiZWxsaXBzZSIpKQ0KYGBgDQoNCg0KIyMjIFdpdGhpbi1ncm91cCBkaXN0YW5jZXMNCg0KYGBge3J9DQojIGNhbGN1bGF0ZSBhbmQgcGxvdCBzYW1wbGUgZGlzdGFuY2VzIHdpdGhpbiBncm91cHMNCnQxJGNhbF9ncm91cF9kaXN0YW5jZSh3aXRoaW5fZ3JvdXAgPSBUUlVFKQ0KIyByZXR1cm4gdDEkcmVzX2dyb3VwX2Rpc3RhbmNlDQojIHBlcmZvcm0gV2lsY294b24gUmFuayBTdW0gYW5kIFNpZ25lZCBSYW5rIFRlc3RzDQp0MSRjYWxfZ3JvdXBfZGlzdGFuY2VfZGlmZihtZXRob2QgPSAid2lsY294IikNCiMgcGxvdF9ncm91cF9vcmRlciBwYXJhbWV0ZXIgY2FuIGJlIHVzZWQgdG8gYWRqdXN0IG9yZGVycyBpbiB4IGF4aXMNCnQxJHBsb3RfZ3JvdXBfZGlzdGFuY2UoYm94cGxvdF9hZGQgPSAibWVhbiIpDQpgYGANCg0KDQoNCiMjIyMgRGlzcGVyc2lvbg0KDQpgYGB7cn0NCiMgZm9yIHRoZSB3aG9sZSBjb21wYXJpc29uIGFuZCBmb3IgZWFjaCBwYWlyZWQgZ3JvdXBzDQp0MSRjYWxfYmV0YWRpc3BlcigpDQojIyBUaGUgcmVzdWx0IGlzIHN0b3JlZCBpbiBvYmplY3QkcmVzX2JldGFkaXNwZXIgLi4uDQp0MSRyZXNfYmV0YWRpc3Blcg0KYGBgDQojIEV4cGxhaW5hYmxlIGNsYXNzDQoNCiMjIFNlY2xlY3QgdmFyaWFibGVzDQoNCmBgYHtyfQ0KI2VudiA8LSBzZWxlY3QobWVjb19kYXQkc2FtcGxlX3RhYmxlLGFsbF9vZihlZmZlY3Quc2l6ZS52YXJpYWJsZXMpKSAlPiUNCiMgIG11dGF0ZShTdHJlc3NfZ3JvdXAgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihTdHJlc3NfZ3JvdXApKSkgJT4lDQojICBzZWxlY3QoLWMoIkJhdGNoIiwiQUIuaW5mYW50IikpICU+JQ0KIyAgc2VsZWN0KHdoZXJlKGlzLm51bWVyaWMpKSAlPiUNCiMgIGRyb3BfbmEoR2VzdGF0aW9uYWwuYWdlKSAlPiUNCiMgIGRyb3BfbmEoKSAlPiUNCiMgIHNlbGVjdF9pZih+ICFhbnkoaXMubmEoLikpKQ0KDQplbnYgPC0gbWVjb19kYXQkc2FtcGxlX3RhYmxlICU+JQ0KICBkcGx5cjo6c2VsZWN0KGtleS52YXJzKSAlPiUNCiAgZHBseXI6OnNlbGVjdCgtVGltZXBvaW50KSAlPiUNCiBkcm9wX25hKCkgJT4lDQogICN0aWR5cjo6ZHJvcF9uYSgpICU+JSAjRHJvcCBhbnkgcm93cyB3aXRoIE5Bcw0KICBkcGx5cjo6bXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgYXMuZmFjdG9yKQ0KDQojRml4IGVudmlyb25tZW50YWwgdmFyaWFibGUgbmFtZXMNCmNvbG5hbWVzKGVudikgPC0gY29sbmFtZXMoZW52KSAlPiUgZ3N1YigiXyIsIiAiLC4pDQoNCnN0cihlbnYpDQoNCmNvbG5hbWVzKGVudikNCmBgYA0KDQoNCkNyZWF0aW5nIHRyYW5zX2VudiBvYmplY3QgDQoNCmBgYHtyLCB3YXJuaW5nID0gRn0NCmVudiRgU2V4IGNoaWxkYCA8LSBlbnYkYFNleCBjaGlsZGAgJT4lIHJlY29kZSgiMCI9IkZlbWFsZSIsIjEiPSJNYWxlIikNCg0KdDEgPC0gdHJhbnNfZW52JG5ldyhkYXRhc2V0ID0gbWVjb19kYXQsDQogICAgICAgICAgICAgICAgICAgIGFkZF9kYXRhID0gZW52KQ0KYGBgDQoNCiMjIFJEQQ0KDQojIyMgR2VudXMNCg0KYGBge3IsIHdhcm5pbmcgPSBGfQ0KIyB1c2UgR2VudXMNCnQxJGNhbF9vcmRpbmF0aW9uKG1ldGhvZCA9ICJSREEiLCB0YXhhX2xldmVsID0gIkdlbnVzIikNCiMgQXMgdGhlIG1haW4gcmVzdWx0cyBvZiBSREEgYXJlIHJlbGF0ZWQgd2l0aCB0aGUgcHJvamVjdGlvbiBhbmQgYW5nbGVzIGJldHdlZW4gZGlmZmVyZW50IGFycm93cywNCiMgd2UgYWRqdXN0IHRoZSBsZW5ndGggb2YgdGhlIGFycm93IHRvIHNob3cgdGhlbSBjbGVhcmx5IHVzaW5nIHNldmVyYWwgcGFyYW1ldGVycy4NCnQxJHRyYW5zX29yZGluYXRpb24oc2hvd190YXhhID0gMTAsIGFkanVzdF9hcnJvd19sZW5ndGggPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICBtaW5fcGVyY19lbnYgPSAwLjIsDQogICAgICAgICAgICAgICAgICAgIG1heF9wZXJjX2VudiA9IDAuNSwNCiAgICAgICAgICAgICAgICAgICAgbWluX3BlcmNfdGF4ID0gMS41LA0KICAgICAgICAgICAgICAgICAgICBtYXhfcGVyY190YXggPSAyLjUNCiAgICAgICAgICAgICAgICAgICAgKQ0KIyB0MSRyZXNfcmRhX3RyYW5zIGlzIHRoZSB0cmFuc2Zvcm1lZCByZXN1bHQgZm9yIHBsb3QNCg0KcmRhLmdyb3VwIDwtIHQxJHBsb3Rfb3JkaW5hdGlvbihwbG90X2NvbG9yID0gIlN0cmVzc19ncm91cCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfdHlwZSA9IGMoInBvaW50IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudl90ZXh0X3NpemUgPSA0LA0KICAgICAgICAgICAgICAgICAgIHRheGFfdGV4dF9zaXplID0gNCwNCiAgICAgICAgICAgICAgICAgICB0YXhhX3RleHRfY29sb3I9ImRhcmtyZWQiLA0KICAgICAgICAgICAgICAgICAgIHRheGFfYXJyb3dfY29sb3I9ImRhcmtyZWQiLA0KICAgICAgICAgICAgICAgICAgIHBvaW50X2FscGhhPTAuMiwNCiAgICAgICAgICAgICAgICAgICB0YXhhX251ZGdlX3ggPSBjKDAsMCwwLC0xNTAsMCwwLDAsMCwwLDApLA0KICAgICAgICAgICAgICAgICAgIHRheGFfbnVkZ2VfeSA9IGMoMCwxMDAsMzAwLDAsLTIwMCwtMTAwLC0xMDAsLTIwMCwyLDApKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIsaGp1c3QgPSAwLjUpLA0KICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkNCiAgICAgICAgI2xlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICAgICAgICApICsNCiAgbGFicyhjb2xvcj0iU3RyZXNzIGdyb3VwIixmaWxsPSIiKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUoZ3VpZGUgPSBGQUxTRSkNCg0KcmRhLmdyb3VwDQpgYGANCg0KIyBTcGVjaWVzIGVudmlyb25tZW50YWwgZmFjdG9ycw0KDQpUaGUgY29ycmVsYXRpb25zIGJldHdlZW4gZW52aXJvbm1lbnRhbCB2YXJpYWJsZXMgYW5kIHRheGEgYXJlIGltcG9ydGFudCBpbiBhbmFseXppbmcgYW5kIGluZmVycmluZyB0aGUgZmFjdG9ycyBhZmZlY3RpbmcgY29tbXVuaXR5IHN0cnVjdHVyZS4gTGV04oCZcyBmaXJzdCBwZXJmb3JtIGEgY29ycmVsYXRpb24gaGVhdG1hcCB1c2luZyByZWxhdGl2ZSBhYnVuZGFuY2UgZGF0YSBhdCBHZW51cyBsZXZlbCB3aXRoIHRoZSBjYWxfY29yIGZ1bmN0aW9uLiBUaGUgcGFyYW1ldGVyIHBfYWRqdXN0X3R5cGUgY2FuIGNvbnRyb2wgdGhlIHAgdmFsdWUgYWRqdXN0bWVudCB0eXBlLg0KDQpgYGB7ciwgd2FybmluZyA9IEZ9DQplbnYgPC0gbWVjb19kYXQkc2FtcGxlX3RhYmxlICU+JSBkcGx5cjo6c2VsZWN0KGtleS52YXJzLmNvcnRpc29sKQ0KDQojZW52IDwtIG1lY29fZGF0JHNhbXBsZV90YWJsZSAlPiUgZHBseXI6OnNlbGVjdChrZXkudmFycy5pbmYpDQojZW52IDwtIG1lY29fZGF0JHNhbXBsZV90YWJsZSAlPiUgZHBseXI6OnNlbGVjdChrZXkudmFycykNCg0KdDEgPC0gdHJhbnNfZW52JG5ldyhkYXRhc2V0ID0gbWVjb19kYXQsIGFkZF9kYXRhID0gZW52KQ0KDQpgYGANCg0KIyMgR2VudXMgdnMgY29ydGlzb2wgbWVhc3VyZXMNCg0KYGBge3IsIHdhcm5pbmcgPSBGfQ0KIyAncF9hZGp1c3RfdHlwZSA9ICJFbnYiJyBtZWFucyBwIGFkanVzdG1lbnQgaXMgcGVyZm9ybWVkIGZvciBlYWNoIGVudmlyb25tZW50YWwgdmFyaWFibGUgc2VwYXJhdGVseS4NCnQxJGNhbF9jb3IodXNlX2RhdGEgPSAiR2VudXMiLCBwX2FkanVzdF9tZXRob2QgPSAiZmRyIiwgcF9hZGp1c3RfdHlwZSA9ICJFbnYiKQ0KYGBgDQoNClRoZW4sIHdlIGNhbiBwbG90IHRoZSBjb3JyZWxhdGlvbiByZXN1bHRzIHVzaW5nIHBsb3RfY29yIGZ1bmN0aW9uLg0KDQpgYGB7ciwgd2FybmluZyA9IEZ9DQojIGRlZmF1bHQgZ2dwbG90MiBtZXRob2Qgd2l0aCBjbHVzdGVyaW5nDQp0MSRwbG90X2NvcihjbHVzdGVyX2dncGxvdCA9ICJib3RoIikNCmBgYA0KDQpUaGVyZSBhcmUgdG9vIG1hbnkgZ2VuZXJhLiBXZSBjYW4gdXNlIHRoZSBmaWx0ZXJfZmVhdHVyZSBwYXJhbWV0ZXIgaW4gcGxvdF9jb3IgdG8gZmlsdGVyIHNvbWUgdGF4YSB0aGF0IGRvIG5vdCBoYXZlIGFueSBzaWduaWZpY2FuY2UgPCAwLjAwMS4NCg0KYGBge3IsIHdhcm5pbmcgPSBGLGV2YWw9Rn0NCiMgZmlsdGVyIGdlbmVyYSB0aGF0IGRvbm90IGhhdmUgYXQgbGVhc3Qgb25lICoqIG9yICoqKg0KdDEkcGxvdF9jb3IoZmlsdGVyX2ZlYXR1cmUgPSBjKCIiKSxjbHVzdGVyX2dncGxvdCA9ICJib3RoIikNCmBgYA0KDQojIyMgU3BsaXQgYnkgdGltZSBwb2ludA0KDQpgYGB7ciwgd2FybmluZyA9IEZ9DQojICdwX2FkanVzdF90eXBlID0gIkVudiInIG1lYW5zIHAgYWRqdXN0bWVudCBpcyBwZXJmb3JtZWQgZm9yIGVhY2ggZW52aXJvbm1lbnRhbCB2YXJpYWJsZSBzZXBhcmF0ZWx5Lg0KdDEkY2FsX2Nvcih1c2VfZGF0YSA9ICJHZW51cyIsIHBfYWRqdXN0X21ldGhvZCA9ICJmZHIiLCBwX2FkanVzdF90eXBlID0gIkVudiIsYnlfZ3JvdXAgPSAiRGF5IikNCmBgYA0KDQpUaGVyZSBhcmUgdG9vIG1hbnkgZ2VuZXJhLiBXZSBjYW4gdXNlIHRoZSBmaWx0ZXJfZmVhdHVyZSBwYXJhbWV0ZXIgaW4gcGxvdF9jb3IgdG8gZmlsdGVyIHNvbWUgdGF4YSB0aGF0IGRvIG5vdCBoYXZlIGFueSBzaWduaWZpY2FuY2UgPCAwLjAwMS4NCg0KYGBge3IsIHdhcm5pbmcgPSBGfQ0KIyBmaWx0ZXIgZ2VuZXJhIHRoYXQgZG9ub3QgaGF2ZSBhdCBsZWFzdCBvbmUgKiogb3IgKioqDQp0MSRwbG90X2NvcihmaWx0ZXJfZmVhdHVyZSA9IGMoIiIpLGNsdXN0ZXJfZ2dwbG90ID0gImJvdGgiLHBoZWF0bWFwID0gRkFMU0UpDQpwZWFyc29uLmNvcnRpc29sLmRheSA8LSB0MSRwbG90X2NvcihmaWx0ZXJfZmVhdHVyZSA9IGMoIiIpLGNsdXN0ZXJfZ2dwbG90ID0gImJvdGgiLHBoZWF0bWFwID0gRkFMU0UpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KDQpTb21ldGltZXMsIGlmIHRoZSB1c2VyIHdhbnRzIHRvIGRvIHRoZSBjb3JyZWxhdGlvbiBhbmFseXNpcyBiZXR3ZWVuIHRoZSBlbnZpcm9ubWVudGFsIGZhY3RvcnMgYW5kIHNvbWUgaW1wb3J0YW50IHRheGEgZGV0ZWN0ZWQgaW4gdGhlIGJpb21hcmtlciBhbmFseXNpcywgcGxlYXNlIHVzZSBvdGhlcl90YXhhIHBhcmFtZXRlciBpbiBjYWxfY29yIGZ1bmN0aW9uLg0KDQpgYGB7ciwgd2FybmluZyA9IEZ9DQojIGZpcnN0IGNyZWF0ZSB0cmFuc19kaWZmIG9iamVjdCBhcyBhIGRlbW9uc3RyYXRpb24NCnQyIDwtIHRyYW5zX2RpZmYkbmV3KGRhdGFzZXQgPSBtZWNvX2RhdCwgbWV0aG9kID0gInJmIiwgZ3JvdXAgPSAiU3RyZXNzX2dyb3VwIiwgdGF4YV9sZXZlbCA9ICJHZW51cyIscF9hZGp1c3RfbWV0aG9kID0gIm5vbmUiKQ0KIyB0aGVuIGNyZWF0ZSB0cmFuc19lbnYgb2JqZWN0DQp0MSA8LSB0cmFuc19lbnYkbmV3KGRhdGFzZXQgPSBtZWNvX2RhdCwgYWRkX2RhdGEgPSBlbnYpDQojIHVzZSBvdGhlcl90YXhhIHRvIHNlbGVjdCB0YXhhIHlvdSBuZWVkDQp0MSRjYWxfY29yKHVzZV9kYXRhID0gIm90aGVyIiwgcF9hZGp1c3RfbWV0aG9kID0gImZkciIsIG90aGVyX3RheGEgPSB0MiRyZXNfZGlmZiRUYXhhKQ0KdDEkcGxvdF9jb3IoKQ0KYGBgDQoNClRoZSBwaGVhdG1hcCBtZXRob2QgaXMgYWxzbyBhdmFpbGFibGUuIE5vdGUgdGhhdCwgYmVzaWRlcyB0aGUgY29sb3JfdmVjdG9yIHBhcmFtZXRlciwgY29sb3JfcGFsZXR0ZSBjYW4gYWxzbyBiZSB1c2VkIHRvIGNvbnRyb2wgY29sb3IgcGFsZXR0ZSB3aXRoIGN1c3RvbWl6ZWQgY29sb3JzLg0KDQpgYGB7ciwgd2FybmluZyA9IEZ9DQojIGNsdXN0ZXJpbmcgaGVhdG1hcDsgcmVxdWlyZSBwaGVhdG1hcCBwYWNrYWdlDQojIExldCdzIHRha2UgYW5vdGhlciBjb2xvciBwYWxsZXRlDQp0MSRwbG90X2NvcihwaGVhdG1hcCA9IFRSVUUsIGNvbG9yX3BhbGV0dGUgPSByZXYoUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKG4gPSA5LCBuYW1lID0gIlJkWWxCdSIpKSkNCmBgYA0KDQpTb21ldGltZXMsIGlmIGl0IGlzIG5lZWRlZCB0byBzdHVkeSB0aGUgY29ycmVsYXRpb25zIGJldHdlZW4gZW52aXJvbm1lbnRhbCB2YXJpYWJsZXMgYW5kIHRheGEgZm9yIGRpZmZlcmVudCBncm91cHMsIGJ5X2dyb3VwIHBhcmFtZXRlciBjYW4gYmUgdXNlZCBmb3IgdGhpcyBnb2FsLg0KDQpgYGB7ciwgd2FybmluZyA9IEZ9DQojIGNhbGN1bGF0ZSBjb3JyZWxhdGlvbnMgZm9yIGRpZmZlcmVudCBncm91cHMgdXNpbmcgcGFyYW1ldGVyIGJ5X2dyb3VwDQp0MSRjYWxfY29yKGJ5X2dyb3VwID0gIlRpbWVwb2ludCIsICBwX2FkanVzdF9tZXRob2QgPSAiZmRyIikNCiMgcmV0dXJuIHQxJHJlc19jb3INCnQxJHBsb3RfY29yKGZpbHRlcl9mZWF0dXJlID0gYygiIiwgIioiKSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KICANCmBgYA0KDQojIEZ1bmN0aW9uYWwgcHJlZGljdGlvbnMNCg0KRWNvbG9naWNhbCByZXNlYXJjaGVycyBhcmUgdXN1YWxseSBpbnRlcmVzdGVkIGluIHRoZSB0aGUgZnVudGlvbmFsIHByb2ZpbGVzIG9mIG1pY3JvYmlhbCBjb21tdW5pdGllcywgYmVjYXVzZSBmdW5jdGlvbmFsIG9yIG1ldGFib2xpYyBkYXRhIGlzIHBvd2VyZnVsIHRvIGV4cGxhaW4gdGhlIHN0cnVjdHVyZSBhbmQgZHluYW1pY3Mgb2YgbWljcm9iaWFsIGNvbW11bml0aWVzLiBBcyBtZXRhZ2Vub21pYyBzZXF1ZW5jaW5nIGlzIGNvbXBsaWNhdGVkIGFuZCBleHBlbnNpdmUsIHVzaW5nIGFtcGxpY29uIHNlcXVlbmNpbmcgZGF0YSB0byBwcmVkaWN0IGZ1bmN0aW9uYWwgcHJvZmlsZXMgaXMgYW4gYWx0ZXJuYXRpdmUgY2hvaWNlLiBTZXZlcmFsIHNvZnR3YXJlIGFyZSBvZnRlbiB1c2VkIGZvciB0aGlzIGdvYWwsIHN1Y2ggYXMgUElDUlVTdCAoTGFuZ2lsbGUgZXQgYWwuIDIwMTMpLCBUYXg0RnVuIChBw59oYXVlciBldCBhbC4gMjAxNSkgYW5kIEZBUFJPVEFYIChTdGlsaWFub3MgTG91Y2EgZXQgYWwuIDIwMTY7IFMuIExvdWNhLCBQYXJmcmV5LCBhbmQgRG9lYmVsaSAyMDE2KS4gVGhlc2UgdG9vbHMgYXJlIGdyZWF0IHRvIGJlIHVzZWQgZm9yIHRoZSBwcmVkaWN0aW9uIG9mIGZ1bmN0aW9uYWwgcHJvZmlsZXMgYmFzZWQgb24gdGhlIHByb2thcnlvdGljIGNvbW11bml0aWVzIGZyb20gc2VxdWVuY2luZyByZXN1bHRzLiBJbiBhZGRpdGlvbiwgaXQgaXMgYWxzbyBpbXBvcnRhbnQgdG8gb2J0YWluIHRoZSB0cmFpdHMgb3IgZnVuY3Rpb25zIGZvciBlYWNoIHRheGEsIG5vdCBqdXN0IHRoZSB3aG9sZSBwcm9maWxlIG9mIGNvbW11bml0aWVzLiBGQVBST1RBWCBkYXRhYmFzZSBpcyBhIGNvbGxlY3Rpb24gb2YgdGhlIHRyYWl0cyBhbmQgZnVuY3Rpb25zIG9mIHByb2thcnlvdGVzIGJhc2VkIG9uIHRoZSBrbm93biByZXNlYXJjaCByZXN1bHRzIHB1Ymxpc2hlZCBpbiBib29rcyBhbmQgbGl0ZXJhdHVyZXMuIFdlIG1hdGNoIHRoZSB0YXhvbm9taWMgaW5mb3JtYXRpb24gb2YgcHJva2FyeW90ZXMgYWdhaW5zdCB0aGlzIGRhdGFiYXNlIHRvIHByZWRpY3QgdGhlIHRyYWl0cyBvZiBwcm9rYXJ5b3RlcyBvbiBiaW9nZW9jaGVtaWNhbCByb2xlcy4gVGhlIE5KQzE5IGRhdGFiYXNlIChMaW0gZXQgYWwuIDIwMjApIGlzIGFsc28gYXZhaWxhYmxlIGZvciBhbmltYWwtYXNzb2NpYXRlZCBwcm9rYXJ5b3RpYyBkYXRhLCBzdWNoIGFzIGh1bWFuIGd1dCBtaWNyb2Jpb3RhLiBXZSBhbHNvIGltcGxlbWVudCB0aGUgRlVOR3VpbGQgKE5ndXllbiBldCBhbC4gMjAxNikgYW5kIEZ1bmdhbFRyYWl0cyAoUMO1bG1lIGV0IGFsLiAyMDIwKSBkYXRhYmFzZXMgdG8gcHJlZGljdCB0aGUgZnVuZ2FsIHRyYWl0cy4gVGhlIGlkZWEgaWRlbnRpZnlpbmcgcHJva2FyeW90aWMgdHJhaXRzIGFuZCBmdW5jdGlvbmFsIHJlZHVuZGFuY3kgd2FzIGluaXRpYWxseSBpbnNwaXJlZCBieSBvdXIgYW5vdGhlciBzdHVkeSAoTGl1IGV0IGFsLiAyMDIyKS4NCg0KV2UgZmlyc3QgaWRlbnRpZnkvcHJlZGljdCB0cmFpdHMgb2YgdGF4YSB3aXRoIHRoZSBwcm9rYXJ5b3RpYyBleGFtcGxlIGRhdGEuDQoNCmBgYHtyLCB3YXJuaW5nID0gRn0NCiMgY3JlYXRlIG9iamVjdCBvZiB0cmFuc19mdW5jDQp0MiA8LSB0cmFuc19mdW5jJG5ldyhtZWNvX2RhdCkNCiMgbWFwcGluZyB0aGUgdGF4b25vbXkgdG8gdGhlIGRhdGFiYXNlDQojIHRoaXMgY2FuIHJlY29nbml6ZSBwcm9rYXJ5b3RlcyBvciBmdW5naSBhdXRvbWF0aWNhbGx5IGlmIHRoZSBuYW1lcyBvZiB0YXhvbm9taWMgbGV2ZWxzIGFyZSBzdGFuZGFyZC4NCiMgZm9yIGZ1bmdpIGV4YW1wbGUsIHNlZSBodHRwczovL2NoaWxpdWJpby5naXRodWIuaW8vbWljcm9lY29fdHV0b3JpYWwvb3RoZXItZGF0YXNldC5odG1sI2Z1bmdpLWRhdGENCiMgZGVmYXVsdCBkYXRhYmFzZSBmb3IgcHJva2FyeW90ZXMgaXMgRkFQUk9UQVggZGF0YWJhc2UNCnQyJGNhbF9zcGVfZnVuYyhwcm9rX2RhdGFiYXNlID0gIkZBUFJPVEFYIikNCmBgYA0KDQpUaGUgcGVyY2VudGFnZXMgb2YgdGhlIE9UVXMgaGF2aW5nIHRoZSBzYW1lIHRyYWl0IGNhbiByZWZsZWN0IHRoZSBmdW5jdGlvbmFsIHJlZHVuZGFuY3kgb2YgdGhpcyBmdW5jdGlvbiBpbiB0aGUgY29tbXVuaXR5Lg0KDQpgYGB7ciwgd2FybmluZyA9IEZ9DQojIGNhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZXMgZm9yIGNvbW11bml0aWVzDQojIGhlcmUgZG8gbm90IGNvbnNpZGVyIHRoZSBhYnVuZGFuY2UNCnQyJGNhbF9zcGVfZnVuY19wZXJjKGFidW5kYW5jZV93ZWlnaHRlZCA9IEZBTFNFKQ0KYGBgDQoNClRoZW4gd2UgYWxzbyB0YWtlIGFuIGV4YW1wbGUgdG8gc2hvdyB0aGUgcGVyY2VudGFnZXMgb2YgdGhlIE9UVXMgZm9yIGVhY2ggdHJhaXQgaW4gbmV0d29yayBtb2R1bGVzLg0KDQpgYGB7ciwgd2FybmluZyA9IEZ9DQojIGNvbnN0cnVjdCBhIG5ldHdvcmsgZm9yIHRoZSBleGFtcGxlDQpuZXR3b3JrIDwtIHRyYW5zX25ldHdvcmskbmV3KGRhdGFzZXQgPSBtZWNvX2RhdCwgY2FsX2NvciA9ICJiYXNlIiwgdGF4YV9sZXZlbCA9ICJPVFUiLCBmaWx0ZXJfdGhyZXMgPSAwLjAwMDEsIGNvcl9tZXRob2QgPSAic3BlYXJtYW4iKQ0KbmV0d29yayRjYWxfbmV0d29yayhwX3RocmVzID0gMC4wMSwgQ09SX2N1dCA9IDAuNykNCm5ldHdvcmskY2FsX21vZHVsZSgpDQojIGNvbnZlcnQgbW9kdWxlIGluZm8gdG8gbWljcm90YWJsZSBvYmplY3QNCm1lY29fbW9kdWxlIDwtIG5ldHdvcmskdHJhbnNfY29tbSh1c2VfY29sID0gIm1vZHVsZSIpDQptZWNvX21vZHVsZV9mdW5jIDwtIHRyYW5zX2Z1bmMkbmV3KG1lY29fbW9kdWxlKQ0KbWVjb19tb2R1bGVfZnVuYyRjYWxfc3BlX2Z1bmMocHJva19kYXRhYmFzZSA9ICJGQVBST1RBWCIpDQptZWNvX21vZHVsZV9mdW5jJGNhbF9zcGVfZnVuY19wZXJjKGFidW5kYW5jZV93ZWlnaHRlZCA9IEZBTFNFKQ0KbWVjb19tb2R1bGVfZnVuYyRwbG90X3NwZV9mdW5jX3BlcmMob3JkZXJfeCA9IHBhc3RlMCgiTSIsIDE6MTApKQ0KYGBgDQoNCiMgRW52aXJvbm1lbnRhbCBmYWN0b3JzIHZzIGZ1bmN0aW9uYWwgcHJlZGljdGlvbnMNCg0KYGBge3IsIHdhcm5pbmcgPSBGLCBtZXNzYWdlPUZ9DQojIHRoZW4gd2UgdHJ5IHRvIGNvcnJlbGF0ZSB0aGUgcmVzX3NwZV9mdW5jX3BlcmMgb2YgY29tbXVuaXRpZXMgdG8gZW52aXJvbm1lbnRhbCB2YXJpYWJsZXMNCnQzIDwtIHRyYW5zX2VudiRuZXcoZGF0YXNldCA9IG1lY29fZGF0LCBhZGRfZGF0YSA9IGVudikNCnQzJGNhbF9jb3IoYWRkX2FidW5kX3RhYmxlID0gdDIkcmVzX3NwZV9mdW5jX3BlcmMsIGNvcl9tZXRob2QgPSAic3BlYXJtYW4iKQ0KdDMkcGxvdF9jb3IocGhlYXRtYXAgPSBUUlVFDQogICAgICAgICAgICAjZmlsdGVyX2ZlYXR1cmUgPSBjKCIiKQ0KICAgICAgICAgICAgKQ0KYGBgDQoNCiMgQXJyYW5nZSBmaWd1cmVzDQoNCiMjIEZpZ3VyZSAzIC0gQmFycGxvdHMsIGFscGhhLGJldGEgZGl2IGFuZCBkaWZmZXJlbnRpYWwgYWJ1bmRhbmNlIGJ5IHN0cmVzcyBncm91cHMNCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OCwgZmlnLmZ1bGx3aWR0aCA9IFRSVUUsd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoY293cGxvdCkNCg0KQSA8LSBiYXJwbG90LmFsbC5zYW1wbGVzK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KQkMgPC0gIHBsb3RfZ3JpZChiYXJwbG90Lmdyb3VwK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksYmFycGxvdC5zdHJlc3MudGltZS5nZW51cyt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLA0KICAgICAgICAgICAgICAgICBucm93ID0gMSwNCiAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQiIsIkMiKSwNCiAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDI1LA0KICAgICAgICAgICAgICAgICBoanVzdCA9IDAuMyx2anVzdCA9IDEsDQogICAgICAgICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEsMS4yKQ0KICAgICAgICAgICAgICAgICApDQoNCkFCQyA8LSBwbG90X2dyaWQoQSxCQywNCiAgICAgICAgICAgICAgICAgbnJvdyA9MiwNCiAgICBsYWJlbHMgPSBjKCJBIiwiIiksbGFiZWxfc2l6ZSA9IDI1LCBoanVzdCA9IDAuMyx2anVzdCA9IDEsDQogICAgcmVsX2hlaWdodHMgPSBjKDEsMS4yKSkNCg0KREUgPC0gIHBsb3RfZ3JpZChhbHBoYS5ncm91cCt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLA0KICAgICAgICAgICAgICAgICBiZXRhLnN0cmVzcywNCiAgICAgICAgICBucm93ID0gMSwNCiAgICAgICAgICBsYWJlbHMgPSBjKCJEIiwiRSIpLA0KICAgICAgICAgIGxhYmVsX3NpemUgPSAyNSwNCiAgICAgICAgICBoanVzdCA9IDAuMywNCiAgICAgICAgICB2anVzdCA9IDEsDQogICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDEsMSksDQogICAgICAgICAgcmVsX3dpZHRocyA9IGMoMSwxKQ0KICAgICAgICAgICkNCg0KRkcgPC0gcGxvdF9ncmlkKHJhYnUuZ3JvdXArdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiksDQogICAgICAgICAgICAgICAgZGVzZXEyLmxvZzJmb2xkLmJveCwNCiAgICAgICAgICAgICAgICBucm93ID0gMSwNCiAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJGIiwiRyIpLA0KICAgICAgICAgICAgICAgIGxhYmVsX3NpemUgPSAyNSwNCiAgICAgICAgICAgICAgICBoanVzdCA9IDAuMyx2anVzdCA9IDENCikNCg0KcGxvdF9ncmlkKA0KICBwbG90X2dyaWQoICNGb3Igc2hhcmVkIGxlZ2VuZA0KICAgIEFCQyxsZWdlbmQuYmFycGxvdC5hbGwsbnJvdz0xLHJlbF93aWR0aHMgPSBjKDYsMSkNCiAgICApLA0KICBERSwNCiAgRkcsDQogIG5yb3c9MywNCiAgcmVsX2hlaWdodHMgPSBjKDEuOCwxLDEuMSkNCikgICsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMCwwLDAsMC41KSwgImNtIikpIA0KDQpnZ3NhdmUoIkZpZ3VyZXMvRmlndXJlIDMucGRmIix3aWR0aCA9IDI1LCBoZWlnaHQgPSAyNywgdW5pdHMgPSAiY20iLCBkcGkgPSA0MDApIA0KDQpnZ3NhdmUoIkZpZ3VyZXMvRmlndXJlIDMudGlmZiIsd2lkdGggPSAyNSwgaGVpZ2h0ID0gMjcsIHVuaXRzID0gImNtIiwgZHBpID0gNDAwLCBjb21wcmVzc2lvbiA9ICJsenciKSANCmBgYA0KDQojIyBGaWd1cmUgUzEgLSBCYXJwbG90cywgYWxwaGEgYmV0YSBkaXYgYnkgdGltZXBvaW50cw0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEYsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04LCBmaWcuZnVsbHdpZHRoID0gVFJVRX0NCmxpYnJhcnkoY293cGxvdCkNCg0KQkMgPC0gIHBsb3RfZ3JpZChiYXJwbG90LmRheXMsYWxwaGEuZGF5cywNCiAgICAgICAgICAgICAgICAgbnJvdyA9IDEsDQogICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkIiLCJDIiksDQogICAgICAgICAgICAgICAgIGxhYmVsX3NpemUgPSAyNSwNCiAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLjMsdmp1c3QgPSAxLA0KICAgICAgICAgICAgICAgICByZWxfd2lkdGhzID0gYygxLDEuMikNCiAgICAgICAgICAgICAgICAgKQ0KDQpERSA8LSAgcGxvdF9ncmlkKGJldGEuZGF5cyt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLGJldGEuc3RyZXNzLmRheSwNCiAgICAgICAgICAgICAgICAgbnJvdyA9IDEsDQogICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkQiLCJFIiksDQogICAgICAgICAgICAgICAgIGxhYmVsX3NpemUgPSAyNSwNCiAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLjMsdmp1c3QgPSAxLA0KICAgICAgICAgICAgICAgICByZWxfd2lkdGhzID0gYygxLDEuMikNCiAgICAgICAgICAgICAgICAgKQ0KDQpwbG90X2dyaWQoYmFycGxvdC5hbGwucGh5bHVtLEJDLERFLA0KICAgICAgICAgICAgICAgICBucm93ID0zLA0KICAgIGxhYmVscyA9IGMoIkEiLCIiLCIiKSxsYWJlbF9zaXplID0gMjUsIGhqdXN0ID0gMC4zLHZqdXN0ID0gMSwNCiAgICByZWxfaGVpZ2h0cyA9IGMoMSwxLDEuMikpICsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMCwwLDAsMC41KSwgImNtIikpIA0KDQpnZ3NhdmUoIkZpZ3VyZXMvRmlndXJlIFMxLnBkZiIsd2lkdGggPSAyNSwgaGVpZ2h0ID0gMjgsIHVuaXRzID0gImNtIiwgZHBpID0gNDAwKSANCg0KZ2dzYXZlKCJGaWd1cmVzL0ZpZ3VyZSBTMS50aWZmIix3aWR0aCA9IDI1LCBoZWlnaHQgPSAyOCwgdW5pdHMgPSAiY20iLCBkcGkgPSA0MDAsIGNvbXByZXNzaW9uID0gImx6dyIpIA0KYGBgDQoNCiMjIEZpZ3VyZSBTMiAtIFJlbGF0aXZlIGFidW5kYW5jZSBieSBzdHJlc3MgZ3JvdXAgYnkgdGltZSBwb2ludCANCg0KYGBge3IsIGV2YWwgPSBULCBpbmNsdWRlID0gVCwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OCwgZmlnLmZ1bGx3aWR0aCA9IFRSVUV9DQogcGxvdF9ncmlkKHJhYnUuZ3JvdXAudGltZSwNCiAgICAgICAgICBucm93ID0gMSwNCiAgICAgICAgICBsYWJlbHMgPSBjKCIiKSwNCiAgICAgICAgICBsYWJlbF9zaXplID0gMjUsIGhqdXN0ID0gMC4zLHZqdXN0ID0gMSwNCiAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMS4yLDIpLA0KICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEsMSkNCiAgICAgICAgICApICsNCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMCwwLDAsMC41KSwgImNtIikpIA0KDQpnZ3NhdmUoIkZpZ3VyZXMvRmlndXJlIFMyLnBkZiIsd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgZHBpID0gNDAwKSANCg0KZ2dzYXZlKCJGaWd1cmVzL0ZpZ3VyZSBTMi50aWZmIix3aWR0aCA9IDI1LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSA0MDAsIGNvbXByZXNzaW9uID0gImx6dyIpIA0KDQpgYGANCg0KIyMgRmlndXJlIDMgLSBNaWNyb2JpYWwgaW50ZXJhY3Rpb25zIC0gcnVuIGluICJBTVNfTWljcm9FY29BbmFseWlzLlJtZCINCg0KT3V0cHV0cyBzYXZlZCwgYW5kIGZpZ3VyZSBtYW51YWxseSBhcnJhbmdlZCBpbiBQb3dlcnBvaW50DQoNCiMjIEZpZ3VyZSBTMyAtIEluZmFudCBvdXRjb21lcyBlZmZlY3Qgc2l6ZQ0KDQpgYGB7ciwgZXZhbCA9IFQsIGluY2x1ZGUgPSBULCBlY2hvID0gRiwgbWVzc2FnZSA9IEZ9DQpwbG90X2dyaWQoDQogIHBsb3RfZ3JpZChmYW5jeS5hbm92YS5iYXIuaW5mK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIixwbG90Lm1hcmdpbiA9IHVuaXQoYygwLDAuMSwwLDApLCAiY20iKSkrZ2d0aXRsZSgiIiksTlVMTCxmYW5jeS5hbm92YS5iYXIuY29ydCxucm93PTMscmVsX2hlaWdodHMgPSBjKDEuMiwwLjEsMSksbGFiZWxzID0gYygiQSIsIiIsIkIiKSxsYWJlbF9zaXplID0gMjUsIGhqdXN0ID0gMC4zLHZqdXN0ID0gMSksDQogIE5VTEwsDQogICAgICAgICAgcGVhcnNvbi5jb3J0aXNvbC5kYXksDQogICAgICAgICAgbnJvdyA9IDEsDQogICAgICAgICAgbGFiZWxzID0gYygiIiwiQyIpLA0KICAgICAgICAgIGxhYmVsX3NpemUgPSAyNSwgaGp1c3QgPSAwLjMsdmp1c3QgPSAxLA0KICAgICAgICAgIHJlbF93aWR0aHMgPSBjKDEsMC4xLDEpDQogICAgICAgICAgKSArDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsMCwwLjUsMC41KSwgImNtIikpDQoNCmdnc2F2ZSgiRmlndXJlcy9GaWd1cmUgUzMucGRmIix3aWR0aCA9IDI1LCBoZWlnaHQgPSAxNSwgdW5pdHMgPSAiY20iLCBkcGkgPSA0MDApIA0KDQpnZ3NhdmUoIkZpZ3VyZXMvRmlndXJlIFMzLnRpZmYiLHdpZHRoID0gMjUsIGhlaWdodCA9IDE1LCB1bml0cyA9ICJjbSIsIGRwaSA9IDQwMCwgY29tcHJlc3Npb24gPSAibHp3IikgDQpgYGANCg0KIyMgRmlndXJlIDUgLSBDbGluaWNhbCBmYWN0b3JzIGFuZCBtaWNyb2Jpb21lIGNvbXBvc2l0aW9uDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGLCBtZXNzYWdlID0gRn0NCnBsb3RfZ3JpZChmYW5jeS5hbm92YS5iYXIubW90aGVyK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksDQogICAgICAgICAgcmRhLmdyb3VwK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSwNCiAgICAgICAgICBucm93ID0gMSwNCiAgICAgICAgICBsYWJlbHMgPSBjKCJBIiwiQiIpLA0KICAgICAgICAgIGxhYmVsX3NpemUgPSAyNSwgaGp1c3QgPSAwLjMsdmp1c3QgPSAxLA0KICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygxLjIsMiksDQogICAgICAgICAgcmVsX3dpZHRocyA9IGMoMSwxLjYpDQogICAgICAgICAgKSArDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDAsMCwwLjUsMC4yKSwgImNtIikpDQoNCmdnc2F2ZSgiRmlndXJlcy9GaWd1cmUgNS5wZGYiLHdpZHRoID0gMjUsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIGRwaSA9IDQwMCkgDQoNCmdnc2F2ZSgiRmlndXJlcy9GaWd1cmUgNS50aWZmIix3aWR0aCA9IDI1LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSA0MDAsIGNvbXByZXNzaW9uID0gImx6dyIpIA0KYGBgDQoNCiMgU2Vzc2lvbiBpbmZvDQoNCmBgYHtyLCBldmFsID0gVCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBGfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBgDQoNCg0K